├── src ├── test │ ├── resources │ │ └── application.properties │ └── java │ │ └── ee │ │ └── carlrobert │ │ └── llm │ │ └── client │ │ ├── http │ │ ├── exchange │ │ │ ├── Exchange.java │ │ │ ├── StreamHttpExchange.java │ │ │ ├── NdJsonStreamHttpExchange.java │ │ │ └── BasicHttpExchange.java │ │ ├── Service.java │ │ ├── expectation │ │ │ ├── Expectation.java │ │ │ ├── BasicExpectation.java │ │ │ ├── StreamExpectation.java │ │ │ └── NdJsonStreamExpectation.java │ │ ├── ResponseEntity.java │ │ └── RequestEntity.java │ │ ├── BaseTest.java │ │ ├── mixin │ │ ├── ExternalService.java │ │ └── ExternalServiceTestMixin.java │ │ ├── util │ │ └── JSONUtil.java │ │ └── YouClientTest.java └── main │ ├── java │ └── ee │ │ └── carlrobert │ │ └── llm │ │ ├── client │ │ ├── BaseError.java │ │ ├── anthropic │ │ │ ├── completion │ │ │ │ ├── ClaudeCompletionMessage.java │ │ │ │ ├── ClaudeSource.java │ │ │ │ ├── ClaudeCompletionStandardMessage.java │ │ │ │ ├── ClaudeMessageTextContent.java │ │ │ │ ├── ClaudeMessageImageContent.java │ │ │ │ ├── ClaudeCompletionRequestThinking.java │ │ │ │ ├── ClaudeMessageContent.java │ │ │ │ ├── ClaudeCompletionErrorDetails.java │ │ │ │ ├── ClaudeCompletionResponseUsage.java │ │ │ │ ├── ClaudeCompletionException.java │ │ │ │ ├── ClaudeMessageToolResultContent.java │ │ │ │ ├── ClaudeMessageToolUseContent.java │ │ │ │ ├── ClaudeCompletionDetailedMessage.java │ │ │ │ ├── ClaudeCompletionResponse.java │ │ │ │ ├── ClaudeCompletionStreamResponse.java │ │ │ │ ├── ClaudeToolChoice.java │ │ │ │ ├── ClaudeBase64Source.java │ │ │ │ ├── ClaudeCompletionResponseMessage.java │ │ │ │ ├── ClaudeCompletionRequest.java │ │ │ │ └── ClaudeTool.java │ │ │ └── ClaudeClient.java │ │ ├── openai │ │ │ ├── completion │ │ │ │ ├── request │ │ │ │ │ ├── OpenAIChatCompletionMessage.java │ │ │ │ │ ├── ResponseFormat.java │ │ │ │ │ ├── Prediction.java │ │ │ │ │ ├── Tool.java │ │ │ │ │ ├── OpenAIMessageContent.java │ │ │ │ │ ├── OpenAIChatCompletionStandardMessage.java │ │ │ │ │ ├── OpenAIMessageTextContent.java │ │ │ │ │ ├── ToolFunction.java │ │ │ │ │ ├── ToolFunctionParameters.java │ │ │ │ │ ├── OpenAIMessageImageURLContent.java │ │ │ │ │ ├── OpenAIChatCompletionDetailedMessage.java │ │ │ │ │ ├── OpenAIChatCompletionToolMessage.java │ │ │ │ │ ├── OpenAIChatCompletionAssistantMessage.java │ │ │ │ │ ├── OpenAIImageUrl.java │ │ │ │ │ └── OpenAITextCompletionRequest.java │ │ │ │ ├── BaseApiResponseError.java │ │ │ │ ├── ApiResponseError.java │ │ │ │ ├── response │ │ │ │ │ ├── OpenAITextCompletionResponseChoice.java │ │ │ │ │ ├── ToolFunctionResponse.java │ │ │ │ │ ├── OpenAITextCompletionResponse.java │ │ │ │ │ ├── OpenAIChatCompletionResponseChoiceDelta.java │ │ │ │ │ ├── OpenAIChatCompletionResponseUsage.java │ │ │ │ │ ├── ToolCall.java │ │ │ │ │ ├── OpenAIChatCompletionResponseChoice.java │ │ │ │ │ └── OpenAIChatCompletionResponse.java │ │ │ │ ├── ErrorDetails.java │ │ │ │ ├── OpenAITextCompletionEventSourceListener.java │ │ │ │ ├── OpenAIChatCompletionModel.java │ │ │ │ └── OpenAIChatCompletionEventSourceListener.java │ │ │ ├── embeddings │ │ │ │ ├── EmbeddingData.java │ │ │ │ ├── EmbeddingResponse.java │ │ │ │ ├── Embedding.java │ │ │ │ └── EmbeddingRequest.java │ │ │ ├── imagegen │ │ │ │ ├── OpenAIImageGenerationModel.java │ │ │ │ └── response │ │ │ │ │ └── OpenAiImageGenerationResponse.java │ │ │ └── response │ │ │ │ ├── response │ │ │ │ └── OpenAIResponseStreamEvent.java │ │ │ │ └── OpenAIResponseTextEventSourceListener.java │ │ ├── codegpt │ │ │ ├── request │ │ │ │ ├── prediction │ │ │ │ │ ├── DirectPredictionRequest.java │ │ │ │ │ ├── PastePredictionRequest.java │ │ │ │ │ ├── AutocompletionPredictionRequest.java │ │ │ │ │ ├── FileDetails.java │ │ │ │ │ └── PredictionRequest.java │ │ │ │ ├── chat │ │ │ │ │ ├── DocumentationDetails.java │ │ │ │ │ ├── Metadata.java │ │ │ │ │ ├── ContextFile.java │ │ │ │ │ └── AdditionalRequestContext.java │ │ │ │ ├── AutoApplyRequest.java │ │ │ │ └── CodeCompletionRequest.java │ │ │ ├── PricingPlan.java │ │ │ ├── response │ │ │ │ ├── AutoApplyResponse.java │ │ │ │ ├── PredictionResponse.java │ │ │ │ └── CodeGPTException.java │ │ │ ├── AvailableModel.java │ │ │ ├── CodeGPTApiResponseError.java │ │ │ └── CodeGPTUserDetails.java │ │ ├── google │ │ │ ├── embedding │ │ │ │ ├── ContentEmbedding.java │ │ │ │ ├── GoogleEmbeddingResponse.java │ │ │ │ ├── GoogleBatchEmbeddingResponse.java │ │ │ │ ├── GoogleEmbeddingContentRequest.java │ │ │ │ └── GoogleEmbeddingRequest.java │ │ │ ├── models │ │ │ │ ├── GoogleTokensResponse.java │ │ │ │ ├── GoogleModel.java │ │ │ │ └── GoogleModelsResponse.java │ │ │ └── completion │ │ │ │ ├── ApiResponseError.java │ │ │ │ ├── GoogleCompletionContent.java │ │ │ │ ├── ErrorDetails.java │ │ │ │ ├── GoogleGenerationConfig.java │ │ │ │ ├── GoogleContentPart.java │ │ │ │ └── GoogleCompletionRequest.java │ │ ├── you │ │ │ ├── completion │ │ │ │ ├── YouCompletionEventListener.java │ │ │ │ ├── YouCompletionRequestMessage.java │ │ │ │ ├── YouThirdPartySearchResult.java │ │ │ │ ├── YouCompletionMode.java │ │ │ │ ├── YouCompletionCustomModel.java │ │ │ │ ├── YouSourceResult.java │ │ │ │ ├── YouSerpResult.java │ │ │ │ ├── YouCompletionResponse.java │ │ │ │ └── YouCompletionRequest.java │ │ │ └── UTMParameters.java │ │ ├── ollama │ │ │ └── completion │ │ │ │ ├── response │ │ │ │ ├── OllamaEmbeddingResponse.java │ │ │ │ ├── OllamaResponseFormat.java │ │ │ │ ├── OllamaTagsResponse.java │ │ │ │ ├── OllamaChatCompletionMessageResponse.java │ │ │ │ ├── OllamaPullResponse.java │ │ │ │ ├── OllamaModelInfoResponse.java │ │ │ │ ├── OllamaCompletionResponse.java │ │ │ │ ├── OllamaModel.java │ │ │ │ └── OllamaChatCompletionResponse.java │ │ │ │ └── request │ │ │ │ ├── OllamaPullRequest.java │ │ │ │ ├── OllamaChatCompletionMessage.java │ │ │ │ ├── OllamaEmbeddingRequest.java │ │ │ │ ├── OllamaChatCompletionRequest.java │ │ │ │ └── OllamaCompletionRequest.java │ │ ├── llama │ │ │ └── completion │ │ │ │ ├── LlamaInfillRequest.java │ │ │ │ ├── LlamaCompletionResponse.java │ │ │ │ └── LlamaCompletionRequest.java │ │ ├── azure │ │ │ ├── AzureCompletionRequestParams.java │ │ │ └── AzureApiResponseError.java │ │ ├── DeserializationUtil.java │ │ ├── inception │ │ │ └── request │ │ │ │ ├── InceptionNextEditRequest.java │ │ │ │ ├── InceptionFIMRequest.java │ │ │ │ └── InceptionApplyRequest.java │ │ └── InterceptorUtil.java │ │ ├── completion │ │ ├── CompletionRequest.java │ │ ├── CompletionResponse.java │ │ ├── CompletionModel.java │ │ └── CompletionEventListener.java │ │ ├── imagegen │ │ ├── ImageGenerationRequest.java │ │ ├── ImageGenerationResponse.java │ │ └── ImageGenerationModel.java │ │ └── PropertiesLoader.java │ └── resources │ └── application.properties ├── settings.gradle.kts ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── .github ├── dependabot.yml └── workflows │ └── staging.yml ├── config └── checkstyle │ └── suppressions.xml ├── .gitignore ├── LICENSE ├── README.md └── gradlew.bat /src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "llm-client" 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlrobertoh/llm-client/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/BaseError.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client; 2 | 3 | public class BaseError { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/completion/CompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.completion; 2 | 3 | public interface CompletionRequest { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/completion/CompletionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.completion; 2 | 3 | public interface CompletionResponse { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/imagegen/ImageGenerationRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.imagegen; 2 | 3 | public interface ImageGenerationRequest { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/imagegen/ImageGenerationResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.imagegen; 2 | 3 | public interface ImageGenerationResponse { 4 | } 5 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/exchange/Exchange.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http.exchange; 2 | 3 | public interface Exchange { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/Service.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http; 2 | 3 | public interface Service { 4 | 5 | String getUrlProperty(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | public interface ClaudeCompletionMessage { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/imagegen/ImageGenerationModel.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.imagegen; 2 | 3 | public interface ImageGenerationModel { 4 | String getCode(); 5 | 6 | String getDescription(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIChatCompletionMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | public interface OpenAIChatCompletionMessage { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/BaseApiResponseError.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion; 2 | 3 | public interface BaseApiResponseError { 4 | 5 | ErrorDetails getError(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/prediction/DirectPredictionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.prediction; 2 | 3 | public class DirectPredictionRequest extends PredictionRequest { 4 | 5 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/completion/CompletionModel.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.completion; 2 | 3 | public interface CompletionModel { 4 | String getCode(); 5 | 6 | String getDescription(); 7 | 8 | int getMaxTokens(); 9 | } 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "gradle" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/ResponseFormat.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | public class ResponseFormat { 4 | 5 | private String type; 6 | 7 | public String getType() { 8 | return type; 9 | } 10 | 11 | public void setType(String type) { 12 | this.type = type; 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/embedding/ContentEmbedding.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.embedding; 2 | 3 | public class ContentEmbedding { 4 | 5 | private double[] values; 6 | 7 | public double[] getValues() { 8 | return values; 9 | } 10 | 11 | public void setValues(double[] values) { 12 | this.values = values; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/PricingPlan.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt; 2 | 3 | public enum PricingPlan { 4 | ANONYMOUS("Anonymous"), FREE("Free"), INDIVIDUAL("Individual"); 5 | 6 | private final String label; 7 | 8 | PricingPlan(String label) { 9 | this.label = label; 10 | } 11 | 12 | public String getLabel() { 13 | return label; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/response/AutoApplyResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.response; 2 | 3 | public class AutoApplyResponse { 4 | 5 | private String mergedCode; 6 | 7 | public String getMergedCode() { 8 | return mergedCode; 9 | } 10 | 11 | public void setMergedCode(String mergedCode) { 12 | this.mergedCode = mergedCode; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouCompletionEventListener.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | import ee.carlrobert.llm.completion.CompletionEventListener; 4 | import java.util.List; 5 | 6 | public interface YouCompletionEventListener extends CompletionEventListener { 7 | 8 | default void onSerpResults(List results) { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/response/PredictionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.response; 2 | 3 | public class PredictionResponse { 4 | 5 | private String nextRevision; 6 | 7 | public String getNextRevision() { 8 | return nextRevision; 9 | } 10 | 11 | public void setNextRevision(String nextRevision) { 12 | this.nextRevision = nextRevision; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaEmbeddingResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | public class OllamaEmbeddingResponse { 4 | 5 | private double[] embedding; 6 | 7 | public double[] getEmbedding() { 8 | return embedding; 9 | } 10 | 11 | public void setEmbedding(double[] embedding) { 12 | this.embedding = embedding; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/expectation/Expectation.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http.expectation; 2 | 3 | import ee.carlrobert.llm.client.http.Service; 4 | 5 | public class Expectation { 6 | 7 | private final Service service; 8 | 9 | public Expectation(Service service) { 10 | this.service = service; 11 | } 12 | 13 | public Service getService() { 14 | return service; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/exchange/StreamHttpExchange.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http.exchange; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import ee.carlrobert.llm.client.http.RequestEntity; 5 | import java.util.List; 6 | 7 | @FunctionalInterface 8 | public interface StreamHttpExchange extends Exchange { 9 | 10 | List getResponse(RequestEntity request) throws JsonProcessingException; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/prediction/PastePredictionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.prediction; 2 | 3 | public class PastePredictionRequest extends PredictionRequest { 4 | 5 | private final String pastedCode; 6 | 7 | public PastePredictionRequest(String pastedCode) { 8 | this.pastedCode = pastedCode; 9 | } 10 | 11 | public String getPastedCode() { 12 | return pastedCode; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/BaseTest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client; 2 | 3 | import ee.carlrobert.llm.client.mixin.ExternalServiceTestMixin; 4 | import org.junit.jupiter.api.AfterEach; 5 | 6 | public abstract class BaseTest implements ExternalServiceTestMixin { 7 | 8 | static { 9 | ExternalServiceTestMixin.init(); 10 | } 11 | 12 | @AfterEach 13 | public void cleanUpEach() { 14 | ExternalServiceTestMixin.clearAll(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/exchange/NdJsonStreamHttpExchange.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http.exchange; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import ee.carlrobert.llm.client.http.RequestEntity; 5 | import java.util.List; 6 | 7 | @FunctionalInterface 8 | public interface NdJsonStreamHttpExchange extends Exchange { 9 | 10 | List getResponse(RequestEntity request) throws JsonProcessingException; 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/exchange/BasicHttpExchange.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http.exchange; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import ee.carlrobert.llm.client.http.RequestEntity; 5 | import ee.carlrobert.llm.client.http.ResponseEntity; 6 | 7 | @FunctionalInterface 8 | public interface BasicHttpExchange extends Exchange { 9 | 10 | ResponseEntity getResponse(RequestEntity request) throws JsonProcessingException; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaResponseFormat.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonValue; 4 | 5 | public enum OllamaResponseFormat { 6 | JSON("json"); 7 | 8 | private final String value; 9 | 10 | OllamaResponseFormat(String value) { 11 | this.value = value; 12 | } 13 | 14 | @JsonValue 15 | public String getValue() { 16 | return value; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeSource.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonSubTypes; 5 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 6 | 7 | @JsonTypeInfo( 8 | use = JsonTypeInfo.Id.NAME, 9 | property = "type") 10 | @JsonSubTypes({ 11 | @JsonSubTypes.Type(value = ClaudeBase64Source.class, name = "base64")}) 12 | public abstract class ClaudeSource { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | codegpt.baseUrl=https://codegpt-api.carlrobert.ee 2 | openai.baseUrl=https://api.openai.com 3 | azure.openai.baseUrl=https://%s.openai.azure.com 4 | anthropic.baseUrl=https://api.anthropic.com 5 | you.baseUrl=https://you.com 6 | llama.baseUrl=http://localhost:8080 7 | ollama.baseUrl=http://localhost:11434 8 | google.baseUrl=https://generativelanguage.googleapis.com 9 | mistral.baseUrl=https://api.mistral.ai 10 | inception.baseUrl=https://api.inceptionlabs.ai 11 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/embeddings/EmbeddingData.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.embeddings; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | public class EmbeddingData { 7 | 8 | private double[] embedding; 9 | 10 | public double[] getEmbedding() { 11 | return embedding; 12 | } 13 | 14 | public void setEmbedding(double[] embedding) { 15 | this.embedding = embedding; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/models/GoogleTokensResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.models; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | public class GoogleTokensResponse { 7 | 8 | private int totalTokens; 9 | 10 | public int getTotalTokens() { 11 | return totalTokens; 12 | } 13 | 14 | public void setTotalTokens(int totalTokens) { 15 | this.totalTokens = totalTokens; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/chat/DocumentationDetails.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.chat; 2 | 3 | public class DocumentationDetails { 4 | 5 | private final String name; 6 | private final String url; 7 | 8 | public DocumentationDetails(String name, String url) { 9 | this.name = name; 10 | this.url = url; 11 | } 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public String getUrl() { 18 | return url; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/Prediction.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | public class Prediction { 4 | 5 | private final String type; 6 | private final String content; 7 | 8 | public Prediction(String type, String content) { 9 | this.type = type; 10 | this.content = content; 11 | } 12 | 13 | public String getType() { 14 | return type; 15 | } 16 | 17 | public String getContent() { 18 | return content; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /config/checkstyle/suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/embeddings/EmbeddingResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.embeddings; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import java.util.List; 5 | 6 | @JsonIgnoreProperties(ignoreUnknown = true) 7 | public class EmbeddingResponse { 8 | 9 | private List data; 10 | 11 | public List getData() { 12 | return data; 13 | } 14 | 15 | public void setData(List data) { 16 | this.data = data; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/embedding/GoogleEmbeddingResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.embedding; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | public class GoogleEmbeddingResponse { 7 | 8 | private ContentEmbedding embedding; 9 | 10 | public ContentEmbedding getEmbedding() { 11 | return embedding; 12 | } 13 | 14 | public void setEmbedding(ContentEmbedding embedding) { 15 | this.embedding = embedding; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouCompletionRequestMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | public class YouCompletionRequestMessage { 4 | 5 | private final String question; 6 | private final String answer; 7 | 8 | public YouCompletionRequestMessage(String question, String answer) { 9 | this.question = question; 10 | this.answer = answer; 11 | } 12 | 13 | public String getQuestion() { 14 | return question; 15 | } 16 | 17 | public String getAnswer() { 18 | return answer; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/Tool.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | public class Tool { 4 | 5 | private String type; 6 | private ToolFunction function; 7 | 8 | public String getType() { 9 | return type; 10 | } 11 | 12 | public void setType(String type) { 13 | this.type = type; 14 | } 15 | 16 | public ToolFunction getFunction() { 17 | return function; 18 | } 19 | 20 | public void setFunction(ToolFunction function) { 21 | this.function = function; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIMessageContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonSubTypes; 4 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 5 | 6 | @JsonTypeInfo( 7 | use = JsonTypeInfo.Id.NAME, 8 | property = "type") 9 | @JsonSubTypes({ 10 | @JsonSubTypes.Type(value = OpenAIMessageTextContent.class, name = "text"), 11 | @JsonSubTypes.Type(value = OpenAIMessageImageURLContent.class, name = "image_url")}) 12 | public abstract class OpenAIMessageContent { 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/expectation/BasicExpectation.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http.expectation; 2 | 3 | import ee.carlrobert.llm.client.http.Service; 4 | import ee.carlrobert.llm.client.http.exchange.BasicHttpExchange; 5 | 6 | public class BasicExpectation extends Expectation { 7 | 8 | private final BasicHttpExchange exchange; 9 | 10 | public BasicExpectation(Service service, BasicHttpExchange exchange) { 11 | super(service); 12 | this.exchange = exchange; 13 | } 14 | 15 | public BasicHttpExchange getExchange() { 16 | return exchange; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionStandardMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | public class ClaudeCompletionStandardMessage implements ClaudeCompletionMessage { 4 | 5 | private final String role; 6 | private final String content; 7 | 8 | public ClaudeCompletionStandardMessage(String role, String content) { 9 | this.role = role; 10 | this.content = content; 11 | } 12 | 13 | public String getRole() { 14 | return role; 15 | } 16 | 17 | public String getContent() { 18 | return content; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/chat/Metadata.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.chat; 2 | 3 | public class Metadata { 4 | 5 | private final String pluginVersion; 6 | private final String platformVersion; 7 | 8 | public Metadata(String pluginVersion, String platformVersion) { 9 | this.pluginVersion = pluginVersion; 10 | this.platformVersion = platformVersion; 11 | } 12 | 13 | public String getPluginVersion() { 14 | return pluginVersion; 15 | } 16 | 17 | public String getPlatformVersion() { 18 | return platformVersion; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/expectation/StreamExpectation.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http.expectation; 2 | 3 | import ee.carlrobert.llm.client.http.Service; 4 | import ee.carlrobert.llm.client.http.exchange.StreamHttpExchange; 5 | 6 | public class StreamExpectation extends Expectation { 7 | 8 | private final StreamHttpExchange exchange; 9 | 10 | public StreamExpectation(Service service, StreamHttpExchange exchange) { 11 | super(service); 12 | this.exchange = exchange; 13 | } 14 | 15 | public StreamHttpExchange getExchange() { 16 | return exchange; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/embedding/GoogleBatchEmbeddingResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.embedding; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import java.util.List; 5 | 6 | @JsonIgnoreProperties(ignoreUnknown = true) 7 | public class GoogleBatchEmbeddingResponse { 8 | 9 | private List embeddings; 10 | 11 | public List getEmbeddings() { 12 | return embeddings; 13 | } 14 | 15 | public void setEmbeddings(List embedding) { 16 | this.embeddings = embedding; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/ResponseEntity.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http; 2 | 3 | public class ResponseEntity { 4 | 5 | private final int statusCode; 6 | private final String response; 7 | 8 | public ResponseEntity(String response) { 9 | this(200, response); 10 | } 11 | 12 | public ResponseEntity(int statusCode, String response) { 13 | this.statusCode = statusCode; 14 | this.response = response; 15 | } 16 | 17 | public int getStatusCode() { 18 | return statusCode; 19 | } 20 | 21 | public String getResponse() { 22 | return response; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIChatCompletionStandardMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | public class OpenAIChatCompletionStandardMessage implements OpenAIChatCompletionMessage { 4 | 5 | private final String role; 6 | private final String content; 7 | 8 | public OpenAIChatCompletionStandardMessage(String role, String content) { 9 | this.role = role; 10 | this.content = content; 11 | } 12 | 13 | public String getRole() { 14 | return role; 15 | } 16 | 17 | public String getContent() { 18 | return content; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeMessageTextContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeName; 4 | 5 | @JsonTypeName("text") 6 | public class ClaudeMessageTextContent extends ClaudeMessageContent { 7 | 8 | private String text; 9 | 10 | public ClaudeMessageTextContent() { 11 | } 12 | 13 | public ClaudeMessageTextContent(String text) { 14 | this.text = text; 15 | } 16 | 17 | public String getText() { 18 | return text; 19 | } 20 | 21 | public void setText(String text) { 22 | this.text = text; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/chat/ContextFile.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.chat; 2 | 3 | public class ContextFile { 4 | 5 | private final String name; 6 | private final String path; 7 | private final String content; 8 | 9 | public ContextFile(String name, String path, String content) { 10 | this.path = path; 11 | this.name = name; 12 | this.content = content; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public String getPath() { 20 | return path; 21 | } 22 | 23 | public String getContent() { 24 | return content; 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/expectation/NdJsonStreamExpectation.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http.expectation; 2 | 3 | import ee.carlrobert.llm.client.http.Service; 4 | import ee.carlrobert.llm.client.http.exchange.NdJsonStreamHttpExchange; 5 | 6 | public class NdJsonStreamExpectation extends Expectation { 7 | 8 | private final NdJsonStreamHttpExchange exchange; 9 | 10 | public NdJsonStreamExpectation(Service service, NdJsonStreamHttpExchange exchange) { 11 | super(service); 12 | this.exchange = exchange; 13 | } 14 | 15 | public NdJsonStreamHttpExchange getExchange() { 16 | return exchange; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIMessageTextContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeName; 4 | 5 | @JsonTypeName("text") 6 | public class OpenAIMessageTextContent extends OpenAIMessageContent { 7 | 8 | private String text; 9 | 10 | public OpenAIMessageTextContent() { 11 | } 12 | 13 | public OpenAIMessageTextContent(String text) { 14 | this.text = text; 15 | } 16 | 17 | public String getText() { 18 | return text; 19 | } 20 | 21 | public void setText(String text) { 22 | this.text = text; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/AutoApplyRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request; 2 | 3 | public class AutoApplyRequest { 4 | 5 | private final String model; 6 | private final String code; 7 | private final String update; 8 | 9 | public AutoApplyRequest(String model, String code, String update) { 10 | this.model = model; 11 | this.code = code; 12 | this.update = update; 13 | } 14 | 15 | public String getModel() { 16 | return model; 17 | } 18 | 19 | public String getCode() { 20 | return code; 21 | } 22 | 23 | public String getUpdate() { 24 | return update; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/llama/completion/LlamaInfillRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.llama.completion; 2 | 3 | public class LlamaInfillRequest extends LlamaCompletionRequest { 4 | 5 | private final String inputPrefix; 6 | private final String inputSuffix; 7 | 8 | public LlamaInfillRequest(Builder builder, String inputPrefix, String inputSuffix) { 9 | super(builder); 10 | this.inputPrefix = inputPrefix; 11 | this.inputSuffix = inputSuffix; 12 | } 13 | 14 | public String getInput_prefix() { 15 | return inputPrefix; 16 | } 17 | 18 | public String getInput_suffix() { 19 | return inputSuffix; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | gradle.properties 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### IntelliJ IDEA ### 9 | *.idea 10 | *.iws 11 | *.iml 12 | *.ipr 13 | out/ 14 | !**/src/main/**/out/ 15 | !**/src/test/**/out/ 16 | 17 | ### Eclipse ### 18 | .apt_generated 19 | .classpath 20 | .factorypath 21 | .project 22 | .settings 23 | .springBeans 24 | .sts4-cache 25 | bin/ 26 | !**/src/main/**/bin/ 27 | !**/src/test/**/bin/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | 39 | ### Mac OS ### 40 | .DS_Store 41 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/embeddings/Embedding.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.embeddings; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class Embedding { 9 | 10 | private final double[] embedding; 11 | 12 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 13 | public Embedding(@JsonProperty("error") double[] embedding) { 14 | this.embedding = embedding; 15 | } 16 | 17 | public double[] getEmbedding() { 18 | return embedding; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeMessageImageContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeName; 4 | 5 | /** 6 | * Messages with image content are supported starting with Claude 3 models. 7 | */ 8 | @JsonTypeName("image") 9 | public class ClaudeMessageImageContent extends ClaudeMessageContent { 10 | 11 | private ClaudeSource source; 12 | 13 | public ClaudeMessageImageContent() { 14 | } 15 | 16 | public ClaudeSource getSource() { 17 | return source; 18 | } 19 | 20 | public ClaudeMessageImageContent(ClaudeSource source) { 21 | this.source = source; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/completion/ApiResponseError.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class ApiResponseError { 9 | 10 | private final ErrorDetails error; 11 | 12 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 13 | public ApiResponseError(@JsonProperty("error") ErrorDetails error) { 14 | this.error = error; 15 | } 16 | 17 | public ErrorDetails getError() { 18 | return error; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionRequestThinking.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class ClaudeCompletionRequestThinking { 6 | 7 | private String type; 8 | @JsonProperty("budget_tokens") 9 | private long budgetTokens; 10 | 11 | public String getType() { 12 | return type; 13 | } 14 | 15 | public void setType(String type) { 16 | this.type = type; 17 | } 18 | 19 | public long getBudgetTokens() { 20 | return budgetTokens; 21 | } 22 | 23 | public void setBudgetTokens(long budgetTokens) { 24 | this.budgetTokens = budgetTokens; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/ApiResponseError.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class ApiResponseError implements BaseApiResponseError { 9 | 10 | private final ErrorDetails error; 11 | 12 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 13 | public ApiResponseError(@JsonProperty("error") ErrorDetails error) { 14 | this.error = error; 15 | } 16 | 17 | public ErrorDetails getError() { 18 | return error; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/response/OpenAITextCompletionResponseChoice.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class OpenAITextCompletionResponseChoice { 9 | 10 | private final String text; 11 | 12 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 13 | public OpenAITextCompletionResponseChoice(@JsonProperty("text") String text) { 14 | this.text = text; 15 | } 16 | 17 | public String getText() { 18 | return text; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/chat/AdditionalRequestContext.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.chat; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class AdditionalRequestContext { 7 | 8 | private final List files; 9 | private final String conversationsHistory; 10 | 11 | public AdditionalRequestContext(List files, String conversationsHistory) { 12 | this.files = files; 13 | this.conversationsHistory = conversationsHistory; 14 | } 15 | 16 | public List getFiles() { 17 | return new ArrayList<>(files); 18 | } 19 | 20 | public String getConversationsHistory() { 21 | return conversationsHistory; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeMessageContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonSubTypes; 4 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 5 | 6 | @JsonTypeInfo( 7 | use = JsonTypeInfo.Id.NAME, 8 | property = "type") 9 | @JsonSubTypes({ 10 | @JsonSubTypes.Type(value = ClaudeMessageTextContent.class, name = "text"), 11 | @JsonSubTypes.Type(value = ClaudeMessageToolUseContent.class, name = "tool_use"), 12 | @JsonSubTypes.Type(value = ClaudeMessageToolResultContent.class, name = "tool_result"), 13 | @JsonSubTypes.Type(value = ClaudeMessageImageContent.class, name = "image")}) 14 | public abstract class ClaudeMessageContent { 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaTagsResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategies; 5 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 6 | import java.util.List; 7 | 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 10 | public class OllamaTagsResponse { 11 | 12 | private List models; 13 | 14 | public List getModels() { 15 | return models; 16 | } 17 | 18 | public void setModels(List models) { 19 | this.models = models; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionErrorDetails.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import ee.carlrobert.llm.client.openai.completion.ErrorDetails; 5 | 6 | @JsonIgnoreProperties(ignoreUnknown = true) 7 | public class ClaudeCompletionErrorDetails { 8 | 9 | private String type; 10 | private ErrorDetails error; 11 | 12 | public String getType() { 13 | return type; 14 | } 15 | 16 | public void setType(String type) { 17 | this.type = type; 18 | } 19 | 20 | public ErrorDetails getError() { 21 | return error; 22 | } 23 | 24 | public void setError(ErrorDetails error) { 25 | this.error = error; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/prediction/AutocompletionPredictionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.prediction; 2 | 3 | public class AutocompletionPredictionRequest extends PredictionRequest { 4 | 5 | private String appliedCompletion; 6 | private String previousRevision; 7 | 8 | public String getAppliedCompletion() { 9 | return appliedCompletion; 10 | } 11 | 12 | public void setAppliedCompletion(String appliedCompletion) { 13 | this.appliedCompletion = appliedCompletion; 14 | } 15 | 16 | public String getPreviousRevision() { 17 | return previousRevision; 18 | } 19 | 20 | public void setPreviousRevision(String previousRevision) { 21 | this.previousRevision = previousRevision; 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/llama/completion/LlamaCompletionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.llama.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import ee.carlrobert.llm.completion.CompletionResponse; 5 | 6 | @JsonIgnoreProperties(ignoreUnknown = true) 7 | public class LlamaCompletionResponse implements CompletionResponse { 8 | 9 | private String content; 10 | private boolean stop; 11 | 12 | public String getContent() { 13 | return content; 14 | } 15 | 16 | public void setContent(String content) { 17 | this.content = content; 18 | } 19 | 20 | public boolean isStop() { 21 | return stop; 22 | } 23 | 24 | public void setStop(boolean stop) { 25 | this.stop = stop; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/mixin/ExternalService.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.mixin; 2 | 3 | import ee.carlrobert.llm.client.http.Service; 4 | 5 | public enum ExternalService implements Service { 6 | CODEGPT("codegpt.baseUrl"), 7 | OPENAI("openai.baseUrl"), 8 | ANTHROPIC("anthropic.baseUrl"), 9 | AZURE("azure.openai.baseUrl"), 10 | YOU("you.baseUrl"), 11 | LLAMA("llama.baseUrl"), 12 | OLLAMA("ollama.baseUrl"), 13 | GOOGLE("google.baseUrl"), 14 | MISTRAL("mistral.baseUrl"), 15 | INCEPTION("inception.baseUrl"); 16 | 17 | private final String urlProperty; 18 | 19 | ExternalService(String urlProperty) { 20 | this.urlProperty = urlProperty; 21 | } 22 | 23 | public String getUrlProperty() { 24 | return urlProperty; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/embeddings/EmbeddingRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.embeddings; 2 | 3 | import java.util.List; 4 | 5 | public class EmbeddingRequest { 6 | 7 | private List input; 8 | private String model = "text-embedding-3-large"; 9 | 10 | public EmbeddingRequest() { 11 | } 12 | 13 | public EmbeddingRequest(String model, List input) { 14 | this.model = model; 15 | this.input = input; 16 | } 17 | 18 | public List getInput() { 19 | return input; 20 | } 21 | 22 | public void setInput(List input) { 23 | this.input = input; 24 | } 25 | 26 | public String getModel() { 27 | return model; 28 | } 29 | 30 | public void setModel(String model) { 31 | this.model = model; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/prediction/FileDetails.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.prediction; 2 | 3 | public class FileDetails { 4 | 5 | private String name; 6 | private String content; 7 | private Long modificationStamp; 8 | 9 | public String getName() { 10 | return name; 11 | } 12 | 13 | public void setName(String name) { 14 | this.name = name; 15 | } 16 | 17 | public String getContent() { 18 | return content; 19 | } 20 | 21 | public void setContent(String content) { 22 | this.content = content; 23 | } 24 | 25 | public Long getModificationStamp() { 26 | return modificationStamp; 27 | } 28 | 29 | public void setModificationStamp(Long modificationStamp) { 30 | this.modificationStamp = modificationStamp; 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/request/OllamaPullRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 5 | 6 | /* 7 | * See ollama/api 8 | */ 9 | @JsonInclude(Include.NON_NULL) 10 | public class OllamaPullRequest { 11 | 12 | private final String name; 13 | private final boolean stream; 14 | 15 | public OllamaPullRequest(String name, boolean stream) { 16 | this.name = name; 17 | this.stream = stream; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public boolean isStream() { 25 | return stream; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/azure/AzureCompletionRequestParams.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.azure; 2 | 3 | public class AzureCompletionRequestParams { 4 | 5 | private final String resourceName; 6 | private final String deploymentId; 7 | private final String apiVersion; 8 | 9 | 10 | public AzureCompletionRequestParams( 11 | String resourceName, 12 | String completionDeploymentId, 13 | String apiVersion) { 14 | this.resourceName = resourceName; 15 | this.deploymentId = completionDeploymentId; 16 | this.apiVersion = apiVersion; 17 | } 18 | 19 | public String getResourceName() { 20 | return resourceName; 21 | } 22 | 23 | public String getDeploymentId() { 24 | return deploymentId; 25 | } 26 | 27 | public String getApiVersion() { 28 | return apiVersion; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/ToolFunction.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | public class ToolFunction { 4 | 5 | private String name; 6 | private String description; 7 | private ToolFunctionParameters parameters; 8 | 9 | public String getName() { 10 | return name; 11 | } 12 | 13 | public void setName(String name) { 14 | this.name = name; 15 | } 16 | 17 | public String getDescription() { 18 | return description; 19 | } 20 | 21 | public void setDescription(String description) { 22 | this.description = description; 23 | } 24 | 25 | public ToolFunctionParameters getParameters() { 26 | return parameters; 27 | } 28 | 29 | public void setParameters(ToolFunctionParameters parameters) { 30 | this.parameters = parameters; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionResponseUsage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | @JsonIgnoreProperties(ignoreUnknown = true) 7 | public class ClaudeCompletionResponseUsage { 8 | 9 | @JsonProperty("input_tokens") 10 | private int inputTokens; 11 | @JsonProperty("output_tokens") 12 | private int outputTokens; 13 | 14 | public int getInputTokens() { 15 | return inputTokens; 16 | } 17 | 18 | public void setInputTokens(int inputTokens) { 19 | this.inputTokens = inputTokens; 20 | } 21 | 22 | public int getOutputTokens() { 23 | return outputTokens; 24 | } 25 | 26 | public void setOutputTokens(int outputTokens) { 27 | this.outputTokens = outputTokens; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/ToolFunctionParameters.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | public class ToolFunctionParameters { 7 | 8 | private String type; 9 | private Map properties; 10 | private List required; 11 | 12 | public String getType() { 13 | return type; 14 | } 15 | 16 | public void setType(String type) { 17 | this.type = type; 18 | } 19 | 20 | public Map getProperties() { 21 | return properties; 22 | } 23 | 24 | public void setProperties(Map properties) { 25 | this.properties = properties; 26 | } 27 | 28 | public List getRequired() { 29 | return required; 30 | } 31 | 32 | public void setRequired(List required) { 33 | this.required = required; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/response/ToolFunctionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class ToolFunctionResponse { 9 | 10 | private final String name; 11 | private final String arguments; 12 | 13 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 14 | public ToolFunctionResponse( 15 | @JsonProperty("name") String name, 16 | @JsonProperty("arguments") String arguments) { 17 | this.name = name; 18 | this.arguments = arguments; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public String getArguments() { 26 | return arguments; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIMessageImageURLContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.fasterxml.jackson.annotation.JsonTypeName; 5 | 6 | /** 7 | * Messages with image content are supported by OpenAIs vision models. 8 | */ 9 | @JsonTypeName("image_url") 10 | public class OpenAIMessageImageURLContent extends OpenAIMessageContent { 11 | 12 | 13 | @JsonProperty("image_url") 14 | private OpenAIImageUrl imageUrl; 15 | 16 | 17 | public OpenAIMessageImageURLContent() { 18 | } 19 | 20 | public OpenAIMessageImageURLContent(OpenAIImageUrl imageUrl) { 21 | this.imageUrl = imageUrl; 22 | } 23 | 24 | 25 | public OpenAIImageUrl getImageUrl() { 26 | return imageUrl; 27 | } 28 | 29 | public void setImageUrl(OpenAIImageUrl imageUrl) { 30 | this.imageUrl = imageUrl; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | assertj = "3.27.3" 3 | awaitility = "4.3.0" 4 | checkstyle = "10.15.0" 5 | commons-io = "2.18.0" 6 | jackson = "2.18.2" 7 | junit = "5.11.4" 8 | okhttp = "5.3.2" 9 | publish-plugin = "2.0.0" 10 | slf4j = "2.0.17" 11 | 12 | [libraries] 13 | assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" } 14 | awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility" } 15 | commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" } 16 | jackson-bom = { module = "com.fasterxml.jackson:jackson-bom", version.ref = "jackson" } 17 | junit-bom = { module = "org.junit:junit-bom", version.ref = "junit" } 18 | okhttp-bom = { module = "com.squareup.okhttp3:okhttp-bom", version.ref = "okhttp" } 19 | slf4j-bom = { module = "org.slf4j:slf4j-bom", version.ref = "slf4j" } 20 | 21 | [plugins] 22 | publish-plugin = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "publish-plugin" } 23 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionException.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | /** 4 | * Exception thrown when there are issues with Claude completion requests or responses. 5 | * This exception provides more specific error information than generic RuntimeException. 6 | */ 7 | public class ClaudeCompletionException extends RuntimeException { 8 | 9 | /** 10 | * Creates a new ClaudeCompletionException with the specified message. 11 | * 12 | * @param message The error message 13 | */ 14 | public ClaudeCompletionException(String message) { 15 | super(message); 16 | } 17 | 18 | /** 19 | * Creates a new ClaudeCompletionException with the specified message and cause. 20 | * 21 | * @param message The error message 22 | * @param cause The underlying cause of the exception 23 | */ 24 | public ClaudeCompletionException(String message, Throwable cause) { 25 | super(message, cause); 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeMessageToolResultContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.fasterxml.jackson.annotation.JsonTypeName; 5 | 6 | /** 7 | * Represents the result of a tool execution in Claude message content. 8 | * This class is used to convey the output of a tool call back to the model. 9 | */ 10 | @JsonTypeName("tool_result") 11 | public class ClaudeMessageToolResultContent extends ClaudeMessageContent { 12 | 13 | @JsonProperty("tool_use_id") 14 | private String toolUseId; 15 | private String content; 16 | 17 | public String getToolUseId() { 18 | return toolUseId; 19 | } 20 | 21 | public void setToolUseId(String toolUseId) { 22 | this.toolUseId = toolUseId; 23 | } 24 | 25 | public String getContent() { 26 | return content; 27 | } 28 | 29 | public void setContent(String content) { 30 | this.content = content; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/completion/CompletionEventListener.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.completion; 2 | 3 | import ee.carlrobert.llm.client.openai.completion.ErrorDetails; 4 | import ee.carlrobert.llm.client.openai.completion.response.ToolCall; 5 | import java.util.List; 6 | import okhttp3.sse.EventSource; 7 | 8 | public interface CompletionEventListener { 9 | 10 | default void onOpen() { 11 | } 12 | 13 | default void onEvent(String data) { 14 | } 15 | 16 | default void onThinking(String thinking) { 17 | } 18 | 19 | default void onMessage(T message, String rawMessage, EventSource eventSource) { 20 | } 21 | 22 | default void onMessage(T message, EventSource eventSource) { 23 | } 24 | 25 | default void onComplete(StringBuilder messageBuilder) { 26 | } 27 | 28 | default void onCancelled(StringBuilder messageBuilder) { 29 | } 30 | 31 | default void onError(ErrorDetails error, Throwable ex) { 32 | } 33 | 34 | default void onToolCall(ToolCall toolCall) { 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouThirdPartySearchResult.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import java.util.List; 7 | 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | public class YouThirdPartySearchResult { 10 | 11 | private final List thirdPartySearchResults; 12 | 13 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 14 | public YouThirdPartySearchResult( 15 | @JsonProperty("third_party_search_results") List thirdPartySearchResults) { 16 | this.thirdPartySearchResults = thirdPartySearchResults; 17 | } 18 | 19 | public boolean hasSearchResults() { 20 | return thirdPartySearchResults != null && !thirdPartySearchResults.isEmpty(); 21 | } 22 | 23 | public List getThirdPartySearchResults() { 24 | return thirdPartySearchResults; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/request/OllamaChatCompletionMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import java.util.List; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | @JsonInclude(JsonInclude.Include.NON_NULL) 9 | public class OllamaChatCompletionMessage { 10 | 11 | private final String role; 12 | private final String content; 13 | private final List images; 14 | 15 | public OllamaChatCompletionMessage(@NotNull String role, @NotNull String content, 16 | @Nullable List images) { 17 | this.role = role; 18 | this.content = content; 19 | this.images = images; 20 | } 21 | 22 | @NotNull 23 | public String getRole() { 24 | return role; 25 | } 26 | 27 | @NotNull 28 | public String getContent() { 29 | return content; 30 | } 31 | 32 | @Nullable 33 | public List getImages() { 34 | return images; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIChatCompletionDetailedMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | public class OpenAIChatCompletionDetailedMessage implements OpenAIChatCompletionMessage { 7 | 8 | private final String role; 9 | private List content; 10 | 11 | public OpenAIChatCompletionDetailedMessage(String role, OpenAIMessageContent content) { 12 | this.role = role; 13 | this.content = Collections.singletonList(content); 14 | } 15 | 16 | public OpenAIChatCompletionDetailedMessage(String role, List content) { 17 | this.role = role; 18 | this.content = content; 19 | } 20 | 21 | public String getRole() { 22 | return role; 23 | } 24 | 25 | public List getContent() { 26 | return content; 27 | } 28 | 29 | public void setContent(List content) { 30 | this.content = content; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/PropertiesLoader.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.Properties; 6 | 7 | public class PropertiesLoader { 8 | 9 | public static String getValue(String key) { 10 | var systemProperty = System.getProperty(key); 11 | if (systemProperty != null) { 12 | return systemProperty; 13 | } 14 | 15 | var value = (String) loadProperties().get(key); 16 | if (value == null) { 17 | return System.getProperty(key); 18 | } 19 | return value; 20 | } 21 | 22 | private static Properties loadProperties() { 23 | try (InputStream inputStream = PropertiesLoader.class 24 | .getClassLoader() 25 | .getResourceAsStream("application.properties")) { 26 | Properties configuration = new Properties(); 27 | configuration.load(inputStream); 28 | return configuration; 29 | } catch (IOException e) { 30 | throw new RuntimeException("Unable to load application properties", e); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeMessageToolUseContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeName; 4 | import java.util.Map; 5 | 6 | /** 7 | * Represents a tool use request in Claude message content. 8 | * This class is used when the model requests to use a tool during the completion. 9 | */ 10 | @JsonTypeName("tool_use") 11 | public class ClaudeMessageToolUseContent extends ClaudeMessageContent { 12 | 13 | private String id; 14 | private String name; 15 | private Map input; 16 | 17 | public String getId() { 18 | return id; 19 | } 20 | 21 | public void setId(String id) { 22 | this.id = id; 23 | } 24 | 25 | public String getName() { 26 | return name; 27 | } 28 | 29 | public void setName(String name) { 30 | this.name = name; 31 | } 32 | 33 | public Map getInput() { 34 | return input; 35 | } 36 | 37 | public void setInput(Map input) { 38 | this.input = input; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/response/CodeGPTException.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | public class CodeGPTException extends RuntimeException { 7 | 8 | private String title; 9 | private int status; 10 | private String detail; 11 | private String instance; 12 | 13 | public String getTitle() { 14 | return title; 15 | } 16 | 17 | public void setTitle(String title) { 18 | this.title = title; 19 | } 20 | 21 | public int getStatus() { 22 | return status; 23 | } 24 | 25 | public void setStatus(int status) { 26 | this.status = status; 27 | } 28 | 29 | public String getDetail() { 30 | return detail; 31 | } 32 | 33 | public void setDetail(String detail) { 34 | this.detail = detail; 35 | } 36 | 37 | public String getInstance() { 38 | return instance; 39 | } 40 | 41 | public void setInstance(String instance) { 42 | this.instance = instance; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIChatCompletionToolMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * Represents a tool result message in the conversation. 7 | * This message type is sent back to the model after executing a tool call. 8 | */ 9 | public class OpenAIChatCompletionToolMessage implements OpenAIChatCompletionMessage { 10 | 11 | private final String name; 12 | @JsonProperty("tool_call_id") 13 | private final String callId; 14 | private final String content; 15 | 16 | public OpenAIChatCompletionToolMessage(String callId, String name, String content) { 17 | this.callId = callId; 18 | this.name = name; 19 | this.content = content; 20 | } 21 | 22 | public String getCallId() { 23 | return callId; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public String getContent() { 31 | return content; 32 | } 33 | 34 | public String getRole() { 35 | return "tool"; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionDetailedMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | public class ClaudeCompletionDetailedMessage implements ClaudeCompletionMessage { 7 | 8 | private String role; 9 | private List content; 10 | 11 | public ClaudeCompletionDetailedMessage(String role, ClaudeMessageContent content) { 12 | this.role = role; 13 | this.content = Collections.singletonList(content); 14 | } 15 | 16 | public ClaudeCompletionDetailedMessage(String role, List content) { 17 | this.role = role; 18 | this.content = content; 19 | } 20 | 21 | public String getRole() { 22 | return role; 23 | } 24 | 25 | public void setRole(String role) { 26 | this.role = role; 27 | } 28 | 29 | public List getContent() { 30 | return content; 31 | } 32 | 33 | public void setContent(List content) { 34 | this.content = content; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/imagegen/OpenAIImageGenerationModel.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.imagegen; 2 | 3 | import ee.carlrobert.llm.imagegen.ImageGenerationModel; 4 | import java.util.Arrays; 5 | 6 | public enum OpenAIImageGenerationModel implements ImageGenerationModel { 7 | DALL_E_2("dall-e-2", "DALL·E 2"), 8 | DALL_E_3("dall-e-3", "DALL·E 3"); 9 | private final String code; 10 | private final String description; 11 | 12 | OpenAIImageGenerationModel(String code, String description) { 13 | this.code = code; 14 | this.description = description; 15 | } 16 | 17 | public String getCode() { 18 | return code; 19 | } 20 | 21 | public String getDescription() { 22 | return description; 23 | } 24 | 25 | 26 | @Override 27 | public String toString() { 28 | return description; 29 | } 30 | 31 | public static OpenAIImageGenerationModel findByCode(String code) { 32 | return Arrays.stream(OpenAIImageGenerationModel.values()) 33 | .filter(item -> item.getCode().equals(code)) 34 | .findFirst().orElseThrow(); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/response/OpenAITextCompletionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import ee.carlrobert.llm.completion.CompletionResponse; 7 | import java.util.List; 8 | 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class OpenAITextCompletionResponse implements CompletionResponse { 11 | 12 | private final String id; 13 | private final List choices; 14 | 15 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 16 | public OpenAITextCompletionResponse( 17 | @JsonProperty("id") String id, 18 | @JsonProperty("choices") List choices) { 19 | this.id = id; 20 | this.choices = choices; 21 | } 22 | 23 | public String getId() { 24 | return id; 25 | } 26 | 27 | public List getChoices() { 28 | return choices; 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/response/response/OpenAIResponseStreamEvent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.response.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | @JsonIgnoreProperties(ignoreUnknown = true) 7 | public class OpenAIResponseStreamEvent { 8 | 9 | private String type; 10 | @JsonProperty("sequence_number") 11 | private Integer sequenceNumber; 12 | private OpenAIResponseCompletionResponse response; 13 | 14 | public String getType() { 15 | return type; 16 | } 17 | 18 | public void setType(String type) { 19 | this.type = type; 20 | } 21 | 22 | public Integer getSequenceNumber() { 23 | return sequenceNumber; 24 | } 25 | 26 | public void setSequenceNumber(Integer sequenceNumber) { 27 | this.sequenceNumber = sequenceNumber; 28 | } 29 | 30 | public OpenAIResponseCompletionResponse getResponse() { 31 | return response; 32 | } 33 | 34 | public void setResponse(OpenAIResponseCompletionResponse response) { 35 | this.response = response; 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Carl-Robert Linnupuu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/embedding/GoogleEmbeddingContentRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.embedding; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 5 | import ee.carlrobert.llm.client.google.completion.GoogleCompletionContent; 6 | import java.util.List; 7 | 8 | @JsonInclude(Include.NON_NULL) 9 | public class GoogleEmbeddingContentRequest extends GoogleEmbeddingRequest { 10 | 11 | private String model; 12 | 13 | public GoogleEmbeddingContentRequest(String content, String model) { 14 | this(new Builder(new GoogleCompletionContent(List.of(content))), model); 15 | } 16 | 17 | public GoogleEmbeddingContentRequest(List contents, String model) { 18 | this(new Builder(new GoogleCompletionContent(contents)), model); 19 | } 20 | 21 | public GoogleEmbeddingContentRequest(Builder builder, String model) { 22 | super(builder); 23 | this.model = model; 24 | } 25 | 26 | public String getModel() { 27 | return model; 28 | } 29 | 30 | public void setModel(String model) { 31 | this.model = model; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouCompletionMode.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | import java.util.Arrays; 4 | 5 | public enum YouCompletionMode { 6 | DEFAULT("default", false), 7 | AGENT("agent", false), 8 | CUSTOM("custom", true), 9 | RESEARCH("research", false); 10 | 11 | private final String code; 12 | private final boolean supportCustomModel; 13 | 14 | YouCompletionMode(String code, boolean supportCustomModel) { 15 | this.code = code; 16 | this.supportCustomModel = supportCustomModel; 17 | } 18 | 19 | public String getCode() { 20 | return code; 21 | } 22 | 23 | public String getDescription() { 24 | return code.substring(0, 1).toUpperCase() + code.substring(1); 25 | } 26 | 27 | public boolean isSupportCustomModel() { 28 | return supportCustomModel; 29 | } 30 | 31 | public String toString() { 32 | return code; 33 | } 34 | 35 | public static YouCompletionMode findByCode(String code) { 36 | return Arrays.stream(YouCompletionMode.values()) 37 | .filter(item -> item.getCode().equals(code)) 38 | .findFirst().orElseThrow(); 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouCompletionCustomModel.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | import java.util.Arrays; 4 | 5 | public enum YouCompletionCustomModel { 6 | GPT_4("gpt_4", "GPT-4"), 7 | GPT_4_TURBO("gpt_4_turbo", "GPT-4 Turbo"), 8 | CLAUDE_INSTANT("claude_instant", "Claude Instant"), 9 | CLAUDE_2("claude_2", "Claude 2"), 10 | GEMINI_PRO("gemini_pro", "Gemini Pro"), 11 | ZEPHYR("zephyr", "Zephyr (uncensored)"); 12 | 13 | private final String model; 14 | private final String description; 15 | 16 | YouCompletionCustomModel(String model, String description) { 17 | this.model = model; 18 | this.description = description; 19 | } 20 | 21 | public String getModel() { 22 | return model; 23 | } 24 | 25 | public String getDescription() { 26 | return description; 27 | } 28 | 29 | public String toString() { 30 | return model; 31 | } 32 | 33 | public static YouCompletionCustomModel findByCode(String code) { 34 | return Arrays.stream(YouCompletionCustomModel.values()) 35 | .filter(item -> item.getModel().equals(code)) 36 | .findFirst().orElseThrow(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/DeserializationUtil.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import ee.carlrobert.llm.client.codegpt.response.CodeGPTException; 6 | import java.io.IOException; 7 | import okhttp3.Response; 8 | 9 | public class DeserializationUtil { 10 | 11 | private DeserializationUtil() { 12 | } 13 | 14 | public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() 15 | .setSerializationInclusion(JsonInclude.Include.NON_NULL); 16 | 17 | public static T mapResponse(Response response, Class clazz) { 18 | var body = response.body(); 19 | if (body == null) { 20 | throw new RuntimeException("Response body is null"); 21 | } 22 | 23 | String json = ""; 24 | try { 25 | json = body.string(); 26 | return OBJECT_MAPPER.readValue(json, clazz); 27 | } catch (IOException ex) { 28 | try { 29 | throw OBJECT_MAPPER.readValue(json, CodeGPTException.class); 30 | } catch (IOException e) { 31 | throw new RuntimeException("Could not deserialize response", ex); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/response/OpenAIChatCompletionResponseChoiceDelta.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import java.util.List; 7 | 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | public class OpenAIChatCompletionResponseChoiceDelta { 10 | 11 | private final String role; 12 | private final String content; 13 | private final List toolCalls; 14 | 15 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 16 | public OpenAIChatCompletionResponseChoiceDelta( 17 | @JsonProperty("role") String role, 18 | @JsonProperty("content") String content, 19 | @JsonProperty("tool_calls") List toolCalls) { 20 | this.role = role; 21 | this.content = content; 22 | this.toolCalls = toolCalls; 23 | } 24 | 25 | public String getRole() { 26 | return role; 27 | } 28 | 29 | public String getContent() { 30 | return content; 31 | } 32 | 33 | public List getToolCalls() { 34 | return toolCalls; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouSourceResult.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import java.net.URL; 7 | 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | public class YouSourceResult { 10 | private final String url; 11 | private final boolean done; 12 | private final boolean isError; 13 | 14 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 15 | public YouSourceResult( 16 | @JsonProperty("url") String url, 17 | @JsonProperty("done") boolean done, 18 | @JsonProperty("isError") boolean isError) { 19 | this.url = url; 20 | this.done = done; 21 | this.isError = isError; 22 | } 23 | 24 | public boolean isValid() { 25 | return done && !isError; 26 | } 27 | 28 | public String toString() { 29 | try { 30 | URL parsedUrl = new URL(url); 31 | String hostName = parsedUrl.getHost(); 32 | 33 | return "[" + hostName + "](" + parsedUrl.toString() + ")"; 34 | } catch (Exception e) { 35 | return url; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIChatCompletionAssistantMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import ee.carlrobert.llm.client.openai.completion.response.ToolCall; 5 | import java.util.List; 6 | 7 | /** 8 | * Represents an assistant message in the conversation. 9 | * This message type can include both content and tool calls. 10 | */ 11 | public class OpenAIChatCompletionAssistantMessage implements OpenAIChatCompletionMessage { 12 | 13 | private final String role = "assistant"; 14 | private final String content; 15 | private final List toolCalls; 16 | 17 | public OpenAIChatCompletionAssistantMessage(String content) { 18 | this(content, null); 19 | } 20 | 21 | public OpenAIChatCompletionAssistantMessage(String content, List toolCalls) { 22 | this.content = content; 23 | this.toolCalls = toolCalls; 24 | } 25 | 26 | public String getRole() { 27 | return role; 28 | } 29 | 30 | public String getContent() { 31 | return content; 32 | } 33 | 34 | @JsonProperty("tool_calls") 35 | public List getToolCalls() { 36 | return toolCalls; 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/response/OpenAIChatCompletionResponseUsage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class OpenAIChatCompletionResponseUsage { 9 | 10 | private final int promptTokens; 11 | private final int completionTokens; 12 | private final int totalTokens; 13 | 14 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 15 | public OpenAIChatCompletionResponseUsage( 16 | @JsonProperty("prompt_tokens") int promptTokens, 17 | @JsonProperty("completion_tokens") int completionTokens, 18 | @JsonProperty("total_tokens") int totalTokens) { 19 | this.promptTokens = promptTokens; 20 | this.completionTokens = completionTokens; 21 | this.totalTokens = totalTokens; 22 | } 23 | 24 | public int getPromptTokens() { 25 | return promptTokens; 26 | } 27 | 28 | public int getCompletionTokens() { 29 | return completionTokens; 30 | } 31 | 32 | public int getTotalTokens() { 33 | return totalTokens; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/response/ToolCall.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class ToolCall { 9 | 10 | private final Integer index; 11 | private final String id; 12 | private final String type; 13 | private final ToolFunctionResponse function; 14 | 15 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 16 | public ToolCall( 17 | @JsonProperty("index") Integer index, 18 | @JsonProperty("id") String id, 19 | @JsonProperty("type") String type, 20 | @JsonProperty("function") ToolFunctionResponse function) { 21 | this.index = index; 22 | this.id = id; 23 | this.type = type; 24 | this.function = function; 25 | } 26 | 27 | public Integer getIndex() { 28 | return index; 29 | } 30 | 31 | public String getId() { 32 | return id; 33 | } 34 | 35 | public String getType() { 36 | return type; 37 | } 38 | 39 | public ToolFunctionResponse getFunction() { 40 | return function; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouSerpResult.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class YouSerpResult { 9 | 10 | private final String url; 11 | private final String name; 12 | private final String snippet; 13 | private final String snippetSource; 14 | 15 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 16 | public YouSerpResult( 17 | @JsonProperty("url") String url, 18 | @JsonProperty("name") String name, 19 | @JsonProperty("snippet") String snippet, 20 | @JsonProperty("snippet_source") String snippetSource) { 21 | this.url = url; 22 | this.name = name; 23 | this.snippet = snippet; 24 | this.snippetSource = snippetSource; 25 | } 26 | 27 | public String getUrl() { 28 | return url; 29 | } 30 | 31 | public String getName() { 32 | return name; 33 | } 34 | 35 | public String getSnippet() { 36 | return snippet; 37 | } 38 | 39 | public String getSnippetSource() { 40 | return snippetSource; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/UTMParameters.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you; 2 | 3 | public class UTMParameters { 4 | 5 | private String id; 6 | private String source; 7 | private String medium; 8 | private String campaign; 9 | private String term; 10 | private String content; 11 | 12 | public String getId() { 13 | return id; 14 | } 15 | 16 | public void setId(String id) { 17 | this.id = id; 18 | } 19 | 20 | public String getSource() { 21 | return source; 22 | } 23 | 24 | public void setSource(String source) { 25 | this.source = source; 26 | } 27 | 28 | public String getMedium() { 29 | return medium; 30 | } 31 | 32 | public void setMedium(String medium) { 33 | this.medium = medium; 34 | } 35 | 36 | public String getCampaign() { 37 | return campaign; 38 | } 39 | 40 | public void setCampaign(String campaign) { 41 | this.campaign = campaign; 42 | } 43 | 44 | public String getTerm() { 45 | return term; 46 | } 47 | 48 | public void setTerm(String term) { 49 | this.term = term; 50 | } 51 | 52 | public String getContent() { 53 | return content; 54 | } 55 | 56 | public void setContent(String content) { 57 | this.content = content; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaChatCompletionMessageResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | import java.util.List; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | public class OllamaChatCompletionMessageResponse { 8 | 9 | private String role; 10 | private String content; 11 | private List images; 12 | 13 | public OllamaChatCompletionMessageResponse() { 14 | } 15 | 16 | public OllamaChatCompletionMessageResponse(@NotNull String role, @NotNull String content, 17 | @Nullable List images) { 18 | this.role = role; 19 | this.content = content; 20 | this.images = images; 21 | } 22 | 23 | @NotNull 24 | public String getRole() { 25 | return role; 26 | } 27 | 28 | public void setRole(@NotNull String role) { 29 | this.role = role; 30 | } 31 | 32 | @NotNull 33 | public String getContent() { 34 | return content; 35 | } 36 | 37 | public void setContent(@NotNull String content) { 38 | this.content = content; 39 | } 40 | 41 | @Nullable 42 | public List getImages() { 43 | return images; 44 | } 45 | 46 | public void setImages(@Nullable List images) { 47 | this.images = images; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/inception/request/InceptionNextEditRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.inception.request; 2 | 3 | import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionMessage; 4 | import ee.carlrobert.llm.completion.CompletionRequest; 5 | import java.util.List; 6 | 7 | public class InceptionNextEditRequest implements CompletionRequest { 8 | 9 | private final String model; 10 | private final List messages; 11 | 12 | private InceptionNextEditRequest(Builder builder) { 13 | this.model = builder.model; 14 | this.messages = builder.messages; 15 | } 16 | 17 | public String getModel() { 18 | return model; 19 | } 20 | 21 | public List getMessages() { 22 | return messages; 23 | } 24 | 25 | public static class Builder { 26 | private String model; 27 | private List messages; 28 | 29 | public Builder setModel(String model) { 30 | this.model = model; 31 | return this; 32 | } 33 | 34 | public Builder setMessages(List messages) { 35 | this.messages = messages; 36 | return this; 37 | } 38 | 39 | public InceptionNextEditRequest build() { 40 | return new InceptionNextEditRequest(this); 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/InterceptorUtil.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client; 2 | 3 | import okhttp3.Interceptor; 4 | import okhttp3.MediaType; 5 | import okhttp3.Response; 6 | import okhttp3.ResponseBody; 7 | import okio.Buffer; 8 | import okio.BufferedSource; 9 | 10 | public class InterceptorUtil { 11 | 12 | public static final Interceptor REWRITE_X_NDJSON_CONTENT_INTERCEPTOR = chain -> { 13 | Response response = chain.proceed(chain.request()); 14 | if ("application/x-ndjson".equals(response.header("Content-Type", ""))) { 15 | try (ResponseBody originalBody = response.body()) { 16 | if (originalBody == null) { 17 | return response; 18 | } 19 | 20 | BufferedSource source = originalBody.source(); 21 | try (Buffer buffer = new Buffer()) { 22 | while (!source.exhausted()) { 23 | String line = source.readUtf8LineStrict(); 24 | buffer.writeUtf8("data: ").writeUtf8(line).writeUtf8("\n\n"); 25 | } 26 | return response.newBuilder() 27 | .header("Content-Type", "text/event-stream") 28 | .body(ResponseBody.create( 29 | buffer.readByteString(), 30 | MediaType.parse("text/event-stream"))) 31 | .build(); 32 | } 33 | } 34 | } 35 | return response; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/response/OpenAIChatCompletionResponseChoice.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class OpenAIChatCompletionResponseChoice { 9 | 10 | private final OpenAIChatCompletionResponseChoiceDelta delta; 11 | private final OpenAIChatCompletionResponseChoiceDelta message; 12 | private final String finishReason; 13 | 14 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 15 | public OpenAIChatCompletionResponseChoice( 16 | @JsonProperty("delta") OpenAIChatCompletionResponseChoiceDelta delta, 17 | @JsonProperty("message") OpenAIChatCompletionResponseChoiceDelta message, 18 | @JsonProperty("finish_reason") String finishReason) { 19 | this.delta = delta; 20 | this.message = message; 21 | this.finishReason = finishReason; 22 | } 23 | 24 | public OpenAIChatCompletionResponseChoiceDelta getDelta() { 25 | return delta; 26 | } 27 | 28 | public OpenAIChatCompletionResponseChoiceDelta getMessage() { 29 | return message; 30 | } 31 | 32 | public String getFinishReason() { 33 | return finishReason; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/AvailableModel.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class AvailableModel { 9 | 10 | private final String name; 11 | private final String code; 12 | private final String type; 13 | private final String tier; 14 | private final String developedBy; 15 | 16 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 17 | public AvailableModel( 18 | @JsonProperty("name") String name, 19 | @JsonProperty("code") String code, 20 | @JsonProperty("type") String type, 21 | @JsonProperty("tier") String tier, 22 | @JsonProperty("developedBy") String developedBy) { 23 | this.name = name; 24 | this.code = code; 25 | this.type = type; 26 | this.tier = tier; 27 | this.developedBy = developedBy; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public String getCode() { 35 | return code; 36 | } 37 | 38 | public String getType() { 39 | return type; 40 | } 41 | 42 | public String getTier() { 43 | return tier; 44 | } 45 | 46 | public String getDevelopedBy() { 47 | return developedBy; 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/response/OpenAIChatCompletionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import ee.carlrobert.llm.completion.CompletionResponse; 7 | import java.util.List; 8 | 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class OpenAIChatCompletionResponse implements CompletionResponse { 11 | 12 | private final String id; 13 | private final List choices; 14 | private final OpenAIChatCompletionResponseUsage usage; 15 | 16 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 17 | public OpenAIChatCompletionResponse( 18 | @JsonProperty("id") String id, 19 | @JsonProperty("choices") List choices, 20 | @JsonProperty("usage") OpenAIChatCompletionResponseUsage usage) { 21 | this.id = id; 22 | this.choices = choices; 23 | this.usage = usage; 24 | } 25 | 26 | public String getId() { 27 | return id; 28 | } 29 | 30 | public List getChoices() { 31 | return choices; 32 | } 33 | 34 | public OpenAIChatCompletionResponseUsage getUsage() { 35 | return usage; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaPullResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategies; 5 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 9 | public class OllamaPullResponse { 10 | 11 | private String status; 12 | private String digest; 13 | /** 14 | * Total amount of bytes. 15 | */ 16 | private Long total; 17 | /** 18 | * Downloaded amount of bytes. 19 | */ 20 | private Long completed; 21 | 22 | public String getStatus() { 23 | return status; 24 | } 25 | 26 | public void setStatus(String status) { 27 | this.status = status; 28 | } 29 | 30 | public String getDigest() { 31 | return digest; 32 | } 33 | 34 | public void setDigest(String digest) { 35 | this.digest = digest; 36 | } 37 | 38 | public Long getTotal() { 39 | return total; 40 | } 41 | 42 | public void setTotal(Long total) { 43 | this.total = total; 44 | } 45 | 46 | public Long getCompleted() { 47 | return completed; 48 | } 49 | 50 | public void setCompleted(Long completed) { 51 | this.completed = completed; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/azure/AzureApiResponseError.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.azure; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import ee.carlrobert.llm.client.openai.completion.BaseApiResponseError; 7 | import ee.carlrobert.llm.client.openai.completion.ErrorDetails; 8 | 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class AzureApiResponseError implements BaseApiResponseError { 11 | 12 | private final int statusCode; 13 | private final String message; 14 | 15 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 16 | public AzureApiResponseError( 17 | @JsonProperty("error") ErrorDetails error, 18 | @JsonProperty("statusCode") int statusCode, 19 | @JsonProperty("message") String message) { 20 | if (error != null) { 21 | this.statusCode = Integer.getInteger(error.getCode(), 0); 22 | this.message = error.getMessage(); 23 | } else { 24 | this.statusCode = statusCode; 25 | this.message = message; 26 | } 27 | } 28 | 29 | public int getStatusCode() { 30 | return statusCode; 31 | } 32 | 33 | public String getMessage() { 34 | return message; 35 | } 36 | 37 | @Override 38 | public ErrorDetails getError() { 39 | return new ErrorDetails(message); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/completion/GoogleCompletionContent.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * See Content. 10 | */ 11 | @JsonInclude(Include.NON_NULL) 12 | public class GoogleCompletionContent { 13 | 14 | private List parts; 15 | private String role; 16 | 17 | public GoogleCompletionContent() { 18 | } 19 | 20 | public GoogleCompletionContent(List texts) { 21 | this(null, texts); 22 | } 23 | 24 | public GoogleCompletionContent(String role, List texts) { 25 | this.parts = texts.stream().map(GoogleContentPart::new).collect(Collectors.toList()); 26 | this.role = role; 27 | } 28 | 29 | public GoogleCompletionContent(List parts, String role) { 30 | this.parts = parts; 31 | this.role = role; 32 | } 33 | 34 | public List getParts() { 35 | return parts; 36 | } 37 | 38 | public void setParts( 39 | List parts) { 40 | this.parts = parts; 41 | } 42 | 43 | public String getRole() { 44 | return role; 45 | } 46 | 47 | public void setRole(String role) { 48 | this.role = role; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/completion/ErrorDetails.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import ee.carlrobert.llm.client.BaseError; 7 | import java.util.StringJoiner; 8 | 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class ErrorDetails extends BaseError { 11 | 12 | private final String message; 13 | private final String status; 14 | private final String code; 15 | 16 | public ErrorDetails(String message) { 17 | this(message, null, null); 18 | } 19 | 20 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 21 | public ErrorDetails( 22 | @JsonProperty("message") String message, 23 | @JsonProperty("status") String status, 24 | @JsonProperty("code") String code) { 25 | this.message = message; 26 | this.status = status; 27 | this.code = code; 28 | } 29 | 30 | public String getMessage() { 31 | return message; 32 | } 33 | 34 | public String getStatus() { 35 | return status; 36 | } 37 | 38 | 39 | public String getCode() { 40 | return code; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return new StringJoiner(", ", ErrorDetails.class.getSimpleName() + "[", "]") 46 | .add("message='" + message + "'") 47 | .add("status='" + status + "'") 48 | .add("code='" + code + "'") 49 | .toString(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/CodeGPTApiResponseError.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonCreator.Mode; 5 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 6 | import com.fasterxml.jackson.annotation.JsonProperty; 7 | import ee.carlrobert.llm.client.openai.completion.BaseApiResponseError; 8 | import ee.carlrobert.llm.client.openai.completion.ErrorDetails; 9 | 10 | @JsonIgnoreProperties(ignoreUnknown = true) 11 | public class CodeGPTApiResponseError implements BaseApiResponseError { 12 | 13 | private final int status; 14 | private final String detail; 15 | private final String type; 16 | private final String code; 17 | 18 | @JsonCreator(mode = Mode.PROPERTIES) 19 | public CodeGPTApiResponseError( 20 | @JsonProperty("status") int status, 21 | @JsonProperty("detail") String detail, 22 | @JsonProperty("type") String type, 23 | @JsonProperty("code") String code) { 24 | this.status = status; 25 | this.detail = detail; 26 | this.type = type; 27 | this.code = code; 28 | } 29 | 30 | public int getStatus() { 31 | return status; 32 | } 33 | 34 | public String getDetail() { 35 | return detail; 36 | } 37 | 38 | public String getType() { 39 | return type; 40 | } 41 | 42 | public String getCode() { 43 | return code; 44 | } 45 | 46 | @Override 47 | public ErrorDetails getError() { 48 | return new ErrorDetails(detail, type, null, code); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/http/RequestEntity.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.http; 2 | 3 | import static ee.carlrobert.llm.client.DeserializationUtil.OBJECT_MAPPER; 4 | 5 | import com.fasterxml.jackson.core.type.TypeReference; 6 | import com.sun.net.httpserver.Headers; 7 | import com.sun.net.httpserver.HttpExchange; 8 | import java.io.IOException; 9 | import java.net.URI; 10 | import java.nio.charset.StandardCharsets; 11 | import java.util.Collections; 12 | import java.util.Map; 13 | import org.apache.commons.io.IOUtils; 14 | 15 | public class RequestEntity { 16 | 17 | private final URI uri; 18 | private final Map body; 19 | private final Headers headers; 20 | private final String method; 21 | 22 | public RequestEntity(HttpExchange exchange) throws IOException { 23 | this.uri = exchange.getRequestURI(); 24 | this.body = toMap(IOUtils.toString(exchange.getRequestBody(), StandardCharsets.UTF_8)); 25 | this.headers = exchange.getRequestHeaders(); 26 | this.method = exchange.getRequestMethod(); 27 | } 28 | 29 | public URI getUri() { 30 | return uri; 31 | } 32 | 33 | public Map getBody() { 34 | return body; 35 | } 36 | 37 | private Map toMap(String json) throws IOException { 38 | if (json == null || json.isEmpty()) { 39 | return Collections.emptyMap(); 40 | } 41 | 42 | return OBJECT_MAPPER.readValue(json, new TypeReference<>() {}); 43 | } 44 | 45 | public Headers getHeaders() { 46 | return headers; 47 | } 48 | 49 | public String getMethod() { 50 | return method; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaModelInfoResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategies; 5 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 6 | import ee.carlrobert.llm.client.ollama.completion.response.OllamaModel.OllamaModelDetails; 7 | 8 | /** 9 | * see ollama/api. 11 | */ 12 | @JsonIgnoreProperties(ignoreUnknown = true) 13 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 14 | public class OllamaModelInfoResponse { 15 | 16 | private String modelfile; 17 | private String parameters; 18 | private String template; 19 | private OllamaModelDetails details; 20 | 21 | public String getModelfile() { 22 | return modelfile; 23 | } 24 | 25 | public void setModelfile(String modelfile) { 26 | this.modelfile = modelfile; 27 | } 28 | 29 | public String getParameters() { 30 | return parameters; 31 | } 32 | 33 | public void setParameters(String parameters) { 34 | this.parameters = parameters; 35 | } 36 | 37 | public String getTemplate() { 38 | return template; 39 | } 40 | 41 | public void setTemplate(String template) { 42 | this.template = template; 43 | } 44 | 45 | public OllamaModelDetails getDetails() { 46 | return details; 47 | } 48 | 49 | public void setDetails(OllamaModelDetails details) { 50 | this.details = details; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/request/OllamaEmbeddingRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 5 | 6 | /* 7 | * See ollama/api 8 | */ 9 | @JsonInclude(Include.NON_NULL) 10 | public class OllamaEmbeddingRequest { 11 | 12 | private final String model; 13 | private final String prompt; 14 | private final OllamaParameters options; 15 | 16 | public OllamaEmbeddingRequest(Builder builder) { 17 | this.prompt = builder.prompt; 18 | this.model = builder.model; 19 | this.options = builder.options; 20 | } 21 | 22 | public String getModel() { 23 | return model; 24 | } 25 | 26 | public String getPrompt() { 27 | return prompt; 28 | } 29 | 30 | public OllamaParameters getOptions() { 31 | return options; 32 | } 33 | 34 | public static class Builder { 35 | 36 | private final String model; 37 | private final String prompt; 38 | private OllamaParameters options = null; 39 | 40 | public Builder(String model, String prompt) { 41 | this.model = model; 42 | this.prompt = prompt; 43 | } 44 | 45 | public OllamaEmbeddingRequest.Builder setOptions(OllamaParameters options) { 46 | this.options = options; 47 | return OllamaEmbeddingRequest.Builder.this; 48 | } 49 | 50 | public OllamaEmbeddingRequest build() { 51 | return new OllamaEmbeddingRequest(this); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/inception/request/InceptionFIMRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.inception.request; 2 | 3 | import ee.carlrobert.llm.completion.CompletionRequest; 4 | 5 | public class InceptionFIMRequest implements CompletionRequest { 6 | 7 | private final String model; 8 | private final String prompt; 9 | private final String suffix; 10 | private final boolean stream; 11 | 12 | private InceptionFIMRequest(Builder builder) { 13 | this.model = builder.model; 14 | this.prompt = builder.prompt; 15 | this.suffix = builder.suffix; 16 | this.stream = builder.stream; 17 | } 18 | 19 | public String getModel() { 20 | return model; 21 | } 22 | 23 | public String getPrompt() { 24 | return prompt; 25 | } 26 | 27 | public String getSuffix() { 28 | return suffix; 29 | } 30 | 31 | public boolean isStream() { 32 | return stream; 33 | } 34 | 35 | public static class Builder { 36 | private String model; 37 | private String prompt; 38 | private String suffix; 39 | private boolean stream = true; 40 | 41 | public Builder setModel(String model) { 42 | this.model = model; 43 | return this; 44 | } 45 | 46 | public Builder setPrompt(String prompt) { 47 | this.prompt = prompt; 48 | return this; 49 | } 50 | 51 | public Builder setSuffix(String suffix) { 52 | this.suffix = suffix; 53 | return this; 54 | } 55 | 56 | public Builder setStream(boolean stream) { 57 | this.stream = stream; 58 | return this; 59 | } 60 | 61 | public InceptionFIMRequest build() { 62 | return new InceptionFIMRequest(this); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import ee.carlrobert.llm.completion.CompletionResponse; 5 | import java.util.List; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class ClaudeCompletionResponse implements CompletionResponse { 9 | 10 | private String id; 11 | private String type; 12 | private String role; 13 | private List content; 14 | private ClaudeCompletionResponseUsage usage; 15 | private String stopReason; 16 | 17 | public String getId() { 18 | return id; 19 | } 20 | 21 | public void setId(String id) { 22 | this.id = id; 23 | } 24 | 25 | public String getType() { 26 | return type; 27 | } 28 | 29 | public void setType(String type) { 30 | this.type = type; 31 | } 32 | 33 | public String getRole() { 34 | return role; 35 | } 36 | 37 | public void setRole(String role) { 38 | this.role = role; 39 | } 40 | 41 | public List getContent() { 42 | return content; 43 | } 44 | 45 | public void setContent(List content) { 46 | this.content = content; 47 | } 48 | 49 | public ClaudeCompletionResponseUsage getUsage() { 50 | return usage; 51 | } 52 | 53 | public void setUsage(ClaudeCompletionResponseUsage usage) { 54 | this.usage = usage; 55 | } 56 | 57 | public String getStopReason() { 58 | return stopReason; 59 | } 60 | 61 | public void setStopReason(String stopReason) { 62 | this.stopReason = stopReason; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaCompletionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategies; 5 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 9 | public class OllamaCompletionResponse { 10 | 11 | private String model; 12 | private String createdAt; 13 | private String response; 14 | private boolean done; 15 | private int promptEvalCount; 16 | private int evalCount; 17 | 18 | public String getModel() { 19 | return model; 20 | } 21 | 22 | public void setModel(String model) { 23 | this.model = model; 24 | } 25 | 26 | public String getCreatedAt() { 27 | return createdAt; 28 | } 29 | 30 | public void setCreatedAt(String createdAt) { 31 | this.createdAt = createdAt; 32 | } 33 | 34 | public String getResponse() { 35 | return response; 36 | } 37 | 38 | public void setResponse(String response) { 39 | this.response = response; 40 | } 41 | 42 | public boolean isDone() { 43 | return done; 44 | } 45 | 46 | public void setDone(boolean done) { 47 | this.done = done; 48 | } 49 | 50 | public int getPromptEvalCount() { 51 | return promptEvalCount; 52 | } 53 | 54 | public void setPromptEvalCount(int promptEvalCount) { 55 | this.promptEvalCount = promptEvalCount; 56 | } 57 | 58 | public int getEvalCount() { 59 | return evalCount; 60 | } 61 | 62 | public void setEvalCount(int evalCount) { 63 | this.evalCount = evalCount; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/CodeGPTUserDetails.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import java.util.List; 7 | 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | public class CodeGPTUserDetails { 10 | 11 | private final String fullName; 12 | private final PricingPlan pricingPlan; 13 | private final List availableModels; 14 | private final List toolWindowModels; 15 | private final String avatarBase64; 16 | 17 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 18 | public CodeGPTUserDetails( 19 | @JsonProperty("fullName") String fullName, 20 | @JsonProperty("pricingPlan") PricingPlan pricingPlan, 21 | @JsonProperty("availableModels") List availableModels, 22 | @JsonProperty("toolWindowModels") List toolWindowModels, 23 | @JsonProperty("avatarBase64") String avatarBase64) { 24 | this.fullName = fullName; 25 | this.pricingPlan = pricingPlan; 26 | this.availableModels = availableModels; 27 | this.toolWindowModels = toolWindowModels; 28 | this.avatarBase64 = avatarBase64; 29 | } 30 | 31 | public String getFullName() { 32 | return fullName; 33 | } 34 | 35 | public PricingPlan getPricingPlan() { 36 | return pricingPlan; 37 | } 38 | 39 | public List getAvailableModels() { 40 | return availableModels; 41 | } 42 | 43 | public List getToolWindowModels() { 44 | return toolWindowModels; 45 | } 46 | 47 | public String getAvatarBase64() { 48 | return avatarBase64; 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/prediction/PredictionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request.prediction; 2 | 3 | import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionMessage; 4 | import java.util.List; 5 | 6 | public class PredictionRequest { 7 | 8 | private String currentRevision; 9 | private int cursorOffset; 10 | private String gitChanges; 11 | private String customPrompt; 12 | private List openFiles; 13 | private List conversationMessages; 14 | 15 | public String getCurrentRevision() { 16 | return currentRevision; 17 | } 18 | 19 | public void setCurrentRevision(String currentRevision) { 20 | this.currentRevision = currentRevision; 21 | } 22 | 23 | public int getCursorOffset() { 24 | return cursorOffset; 25 | } 26 | 27 | public void setCursorOffset(int cursorOffset) { 28 | this.cursorOffset = cursorOffset; 29 | } 30 | 31 | public String getGitChanges() { 32 | return gitChanges; 33 | } 34 | 35 | public void setGitChanges(String gitChanges) { 36 | this.gitChanges = gitChanges; 37 | } 38 | 39 | public String getCustomPrompt() { 40 | return customPrompt; 41 | } 42 | 43 | public void setCustomPrompt(String customPrompt) { 44 | this.customPrompt = customPrompt; 45 | } 46 | 47 | public List getOpenFiles() { 48 | return openFiles; 49 | } 50 | 51 | public void setOpenFiles(List openFiles) { 52 | this.openFiles = openFiles; 53 | } 54 | 55 | public List getConversationMessages() { 56 | return conversationMessages; 57 | } 58 | 59 | public void setConversationMessages(List conversationMessages) { 60 | this.conversationMessages = conversationMessages; 61 | } 62 | } -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/util/JSONUtil.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.util; 2 | 3 | 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import static ee.carlrobert.llm.client.DeserializationUtil.OBJECT_MAPPER; 11 | 12 | public class JSONUtil { 13 | 14 | @SafeVarargs 15 | public static String jsonMapResponse(Map.Entry... entries) { 16 | try { 17 | return OBJECT_MAPPER.writeValueAsString(Map.ofEntries(entries)); 18 | } catch (JsonProcessingException e) { 19 | throw new RuntimeException("Unable to map to json string", e); 20 | } 21 | } 22 | 23 | public static String jsonMapResponse(String key, Object value) { 24 | if (value == null) { 25 | return String.format("{\"%s\": null}", key); 26 | } 27 | return jsonMapResponse(e(key, value)); 28 | } 29 | 30 | @SafeVarargs 31 | public static Map jsonMap(Map.Entry... entries) { 32 | return Map.ofEntries(entries); 33 | } 34 | 35 | public static Map jsonMap(String key, Object value) { 36 | if (value == null) { 37 | Map contentNull = new HashMap<>(); 38 | contentNull.put(key, null); 39 | return contentNull; // {"key": null} 40 | } 41 | return jsonMap(e(key, value)); 42 | } 43 | 44 | @SafeVarargs 45 | public static List jsonArray(Map... objects) { 46 | List list = new ArrayList<>(); 47 | if (objects == null) { 48 | list.add(null); // [null] 49 | } else { 50 | for (int i = 0; i < objects.length; i++) { 51 | list.add(objects[i]); 52 | } 53 | } 54 | return list; 55 | } 56 | 57 | public static Map.Entry e(String key, Object value) { 58 | return Map.entry(key, value); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionStreamResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import ee.carlrobert.llm.completion.CompletionResponse; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class ClaudeCompletionStreamResponse implements CompletionResponse { 9 | 10 | private String type; 11 | private int index; 12 | private ClaudeCompletionResponseMessage delta; 13 | @JsonProperty("content_block") 14 | private ClaudeCompletionResponseMessage contentBlock; 15 | 16 | public String getType() { 17 | return type; 18 | } 19 | 20 | public void setType(String type) { 21 | this.type = type; 22 | } 23 | 24 | public int getIndex() { 25 | return index; 26 | } 27 | 28 | public void setIndex(int index) { 29 | this.index = index; 30 | } 31 | 32 | public ClaudeCompletionResponseMessage getDelta() { 33 | return delta; 34 | } 35 | 36 | public void setDelta(ClaudeCompletionResponseMessage delta) { 37 | this.delta = delta; 38 | } 39 | 40 | public ClaudeCompletionResponseMessage getContentBlock() { 41 | return contentBlock; 42 | } 43 | 44 | public void setContentBlock(ClaudeCompletionResponseMessage contentBlock) { 45 | this.contentBlock = contentBlock; 46 | } 47 | 48 | public boolean isToolUseContentBlockStart() { 49 | return "content_block_start".equals(type) 50 | && contentBlock != null 51 | && "tool_use".equals(contentBlock.getType()); 52 | } 53 | 54 | public boolean isToolUseDelta() { 55 | return "content_block_delta".equals(type) 56 | && delta != null 57 | && delta.getPartialJson() != null; 58 | } 59 | 60 | public boolean isContentBlockStop() { 61 | return "content_block_stop".equals(type); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeToolChoice.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * Represents a tool choice configuration for Claude completions. 7 | * This class specifies how the model should handle tool usage in responses. 8 | */ 9 | public class ClaudeToolChoice { 10 | 11 | private final String type; 12 | private final String name; 13 | 14 | public ClaudeToolChoice(String type, String name) { 15 | this.type = Objects.requireNonNull(type, "Type cannot be null"); 16 | 17 | if ("tool".equals(type) && name == null) { 18 | throw new IllegalArgumentException("Tool name is required when type is 'tool'"); 19 | } 20 | 21 | this.name = name; 22 | } 23 | 24 | public static ClaudeToolChoice auto() { 25 | return new ClaudeToolChoice("auto", null); 26 | } 27 | 28 | public static ClaudeToolChoice any() { 29 | return new ClaudeToolChoice("any", null); 30 | } 31 | 32 | public static ClaudeToolChoice tool(String toolName) { 33 | return new ClaudeToolChoice("tool", toolName); 34 | } 35 | 36 | public String getType() { 37 | return type; 38 | } 39 | 40 | public String getName() { 41 | return name; 42 | } 43 | 44 | @Override 45 | public boolean equals(Object obj) { 46 | if (this == obj) { 47 | return true; 48 | } 49 | if (obj == null || getClass() != obj.getClass()) { 50 | return false; 51 | } 52 | ClaudeToolChoice that = (ClaudeToolChoice) obj; 53 | return Objects.equals(type, that.type) && Objects.equals(name, that.name); 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | return Objects.hash(type, name); 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "ClaudeToolChoice{" 64 | + "type='" + type + '\'' 65 | + ", name='" + name + '\'' 66 | + '}'; 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeBase64Source.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonGetter; 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import com.fasterxml.jackson.annotation.JsonSetter; 7 | import com.fasterxml.jackson.annotation.JsonTypeName; 8 | import java.util.Base64; 9 | 10 | /** 11 | * Represents a base64-encoded data source in Claude. 12 | *
13 | * Allowed media types include the following: 14 | * image/jpeg, image/png, image/gif, and image/webp 15 | */ 16 | @JsonTypeName("base64") 17 | public class ClaudeBase64Source extends ClaudeSource { 18 | @JsonProperty("media_type") 19 | private String mediaType; 20 | private byte[] data; 21 | 22 | public ClaudeBase64Source(String mediaType, byte[] data) { 23 | this.mediaType = mediaType; 24 | this.data = data; 25 | } 26 | 27 | public ClaudeBase64Source() { 28 | } 29 | 30 | public String getMediaType() { 31 | return mediaType; 32 | } 33 | 34 | public void setMediaType(String mediaType) { 35 | this.mediaType = mediaType; 36 | } 37 | 38 | @JsonIgnore 39 | public byte[] getData() { 40 | return this.data; 41 | } 42 | 43 | @JsonIgnore 44 | public void setData(byte[] data) { 45 | this.data = data; 46 | } 47 | 48 | /** 49 | * Gets the data as base64 encoded string. 50 | * 51 | * @return the data 52 | */ 53 | @JsonGetter("data") 54 | public String getBase64EncodedData() { 55 | return Base64.getEncoder().encodeToString(this.data); 56 | } 57 | 58 | /** 59 | * Sets the data. Only base64 encoded strings should be used. 60 | * 61 | * @param base64Data base64 encoded data 62 | */ 63 | @JsonSetter("data") 64 | public void setBase64EncodedData(String base64Data) { 65 | this.data = Base64.getDecoder().decode(base64Data); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/ErrorDetails.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import ee.carlrobert.llm.client.BaseError; 7 | import java.util.StringJoiner; 8 | 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class ErrorDetails extends BaseError { 11 | 12 | private static final String DEFAULT_ERROR_MSG = "Something went wrong. Please try again later."; 13 | 14 | private final String message; 15 | private final String type; 16 | private final String param; 17 | private final String code; 18 | 19 | public ErrorDetails(String message) { 20 | this(message, null, null, null); 21 | } 22 | 23 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 24 | public ErrorDetails( 25 | @JsonProperty("message") String message, 26 | @JsonProperty("type") String type, 27 | @JsonProperty("param") String param, 28 | @JsonProperty("code") String code) { 29 | this.message = message; 30 | this.type = type; 31 | this.param = param; 32 | this.code = code; 33 | } 34 | 35 | public static ErrorDetails DEFAULT_ERROR = new ErrorDetails(DEFAULT_ERROR_MSG); 36 | 37 | public String getMessage() { 38 | return message; 39 | } 40 | 41 | public String getType() { 42 | return type; 43 | } 44 | 45 | public String getParam() { 46 | return param; 47 | } 48 | 49 | public String getCode() { 50 | return code; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return new StringJoiner(", ", ErrorDetails.class.getSimpleName() + "[", "]") 56 | .add("message='" + message + "'") 57 | .add("type='" + type + "'") 58 | .add("param='" + param + "'") 59 | .add("code='" + code + "'") 60 | .toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/inception/request/InceptionApplyRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.inception.request; 2 | 3 | import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionMessage; 4 | import ee.carlrobert.llm.completion.CompletionRequest; 5 | import java.util.List; 6 | 7 | public class InceptionApplyRequest implements CompletionRequest { 8 | 9 | private final String model; 10 | private final List messages; 11 | private final boolean stream; 12 | private final boolean diffusing; 13 | 14 | private InceptionApplyRequest(Builder builder) { 15 | this.model = builder.model; 16 | this.messages = builder.messages; 17 | this.stream = builder.stream; 18 | this.diffusing = builder.diffusing; 19 | } 20 | 21 | public String getModel() { 22 | return model; 23 | } 24 | 25 | public List getMessages() { 26 | return messages; 27 | } 28 | 29 | public boolean isStream() { 30 | return stream; 31 | } 32 | 33 | public boolean isDiffusing() { 34 | return diffusing; 35 | } 36 | 37 | public static class Builder { 38 | private String model; 39 | private List messages; 40 | private boolean stream; 41 | private boolean diffusing; 42 | 43 | public Builder setModel(String model) { 44 | this.model = model; 45 | return this; 46 | } 47 | 48 | public Builder setMessages(List messages) { 49 | this.messages = messages; 50 | return this; 51 | } 52 | 53 | public Builder setStream(boolean stream) { 54 | this.stream = stream; 55 | return this; 56 | } 57 | 58 | public Builder setDiffusing(boolean diffusing) { 59 | this.diffusing = diffusing; 60 | return this; 61 | } 62 | 63 | public InceptionApplyRequest build() { 64 | return new InceptionApplyRequest(this); 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionResponseMessage.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import java.util.Map; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class ClaudeCompletionResponseMessage { 9 | 10 | private String type; 11 | private String text; 12 | private String thinking; 13 | private String id; 14 | private String name; 15 | private Map input; 16 | @JsonProperty("partial_json") 17 | private String partialJson; 18 | 19 | public String getType() { 20 | return type; 21 | } 22 | 23 | public void setType(String type) { 24 | this.type = type; 25 | } 26 | 27 | public String getText() { 28 | return text; 29 | } 30 | 31 | public void setText(String text) { 32 | this.text = text; 33 | } 34 | 35 | public String getThinking() { 36 | return thinking; 37 | } 38 | 39 | public void setThinking(String thinking) { 40 | this.thinking = thinking; 41 | } 42 | 43 | public String getId() { 44 | return id; 45 | } 46 | 47 | public void setId(String id) { 48 | this.id = id; 49 | } 50 | 51 | public String getName() { 52 | return name; 53 | } 54 | 55 | public void setName(String name) { 56 | this.name = name; 57 | } 58 | 59 | public Map getInput() { 60 | return input; 61 | } 62 | 63 | public void setInput(Map input) { 64 | this.input = input; 65 | } 66 | 67 | public String getPartialJson() { 68 | return partialJson; 69 | } 70 | 71 | public void setPartialJson(String partialJson) { 72 | this.partialJson = partialJson; 73 | } 74 | 75 | public boolean isToolUse() { 76 | return "tool_use".equals(type); 77 | } 78 | 79 | public boolean isTextDelta() { 80 | return "text_delta".equals(type); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/OpenAITextCompletionEventSourceListener.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion; 2 | 3 | import static ee.carlrobert.llm.client.DeserializationUtil.OBJECT_MAPPER; 4 | 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import ee.carlrobert.llm.client.openai.completion.response.OpenAITextCompletionResponse; 7 | import ee.carlrobert.llm.client.openai.completion.response.OpenAITextCompletionResponseChoice; 8 | import ee.carlrobert.llm.completion.CompletionEventListener; 9 | import ee.carlrobert.llm.completion.CompletionEventSourceListener; 10 | import java.util.Objects; 11 | import java.util.stream.Stream; 12 | 13 | public class OpenAITextCompletionEventSourceListener extends CompletionEventSourceListener { 14 | 15 | public OpenAITextCompletionEventSourceListener(CompletionEventListener listeners) { 16 | super(listeners); 17 | } 18 | 19 | /** 20 | * Text of the first choice. 21 | *
    22 | *
  • Search all choices which are not null
  • 23 | *
  • Use first text which is not null or blank (whitespace)
  • 24 | *
  • Otherwise use "" (empty string) if no match can be found
  • 25 | *
26 | * 27 | * @return First non-blank content which can be found, otherwise {@code ""} 28 | */ 29 | protected String getMessage(String data) throws JsonProcessingException { 30 | var choices = OBJECT_MAPPER 31 | .readValue(data, OpenAITextCompletionResponse.class) 32 | .getChoices(); 33 | return (choices == null ? Stream.empty() : choices.stream()) 34 | .filter(Objects::nonNull) 35 | .map(OpenAITextCompletionResponseChoice::getText) 36 | .filter(Objects::nonNull) 37 | .findFirst() 38 | .orElse(""); 39 | } 40 | 41 | @Override 42 | protected ErrorDetails getErrorDetails(String data) throws JsonProcessingException { 43 | return OBJECT_MAPPER.readValue(data, ApiResponseError.class).getError(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.github/workflows/staging.yml: -------------------------------------------------------------------------------- 1 | name: Staging 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ '**' ] 8 | 9 | jobs: 10 | build: 11 | name: Build 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v4 18 | with: 19 | java-version: '11' 20 | distribution: 'temurin' 21 | - name: Build with Gradle 22 | # Build and dry-run maven-publish (metadata and pom, but no signing) 23 | run: ./gradlew build generateMetadataFileForMavenJavaPublication generatePomFileForMavenJavaPublication --no-daemon 24 | - name: Run Trivy vulnerability scanner 25 | uses: aquasecurity/trivy-action@0.30.0 26 | with: 27 | ignore-unfixed: true 28 | scan-ref: 'build/publications/mavenJava' 29 | scan-type: 'fs' 30 | scanners: 'vuln' 31 | severity: 'MEDIUM,HIGH,CRITICAL' 32 | env: 33 | TRIVY_FILE_PATTERNS: "pom:pom.*.xml" 34 | TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db,aquasec/trivy-db,ghcr.io/aquasecurity/trivy-db 35 | TRIVY_JAVA_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-java-db,aquasec/trivy-java-db,ghcr.io/aquasecurity/trivy-java-db 36 | 37 | publish: 38 | name: Publish Artifacts 39 | runs-on: ubuntu-latest 40 | needs: [build] 41 | 42 | if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master' 43 | steps: 44 | - uses: actions/checkout@v4 45 | - name: Set up JDK 11 46 | uses: actions/setup-java@v4 47 | with: 48 | java-version: '11' 49 | distribution: 'temurin' 50 | - name: Publish with Gradle 51 | env: 52 | ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} 53 | ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} 54 | ORG_GRADLE_PROJECT_signingKey: ${{ secrets.PGP_SECRET }} 55 | ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.PGP_PASSPHRASE }} 56 | run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository --no-daemon 57 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/OpenAIChatCompletionModel.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion; 2 | 3 | import ee.carlrobert.llm.completion.CompletionModel; 4 | import java.util.Arrays; 5 | 6 | public enum OpenAIChatCompletionModel implements CompletionModel { 7 | GPT_3_5("gpt-3.5-turbo", "GPT-3.5 (4k)", 4096), 8 | GPT_3_5_1106_16k("gpt-3.5-turbo-1106", "GPT-3.5 Turbo (Legacy) (16k)", 16384), 9 | GPT_3_5_0125_16k("gpt-3.5-turbo-0125", "GPT-3.5 Turbo (16k)", 16384), 10 | GPT_4("gpt-4", "GPT-4 (8k)", 8192), 11 | GPT_4_32k("gpt-4-32k", "GPT-4 (32k)", 32768), 12 | GPT_4_1106_128k("gpt-4-1106-preview", "GPT-4 Turbo (Legacy) (128k)", 128000), 13 | GPT_4_0125_128k("gpt-4-0125-preview", "GPT-4 Turbo (128k)", 128000), 14 | GPT_4_VISION_PREVIEW("gpt-4-vision-preview", "GPT-4 Vision Preview (128k)", 128000), 15 | GPT_4_O_MINI("gpt-4o-mini", "GPT-4o mini (128k)", 128000), 16 | GPT_4_O("gpt-4o", "GPT-4o (128k)", 128000), 17 | GPT_4_1("gpt-4.1", "GPT-4.1 (1M)", 1047576), 18 | GPT_4_1_MINI("gpt-4.1-mini", "GPT-4.1-mini (1M)", 1047576), 19 | GPT_4_1_NANO("gpt-4.1-nano", "GPT-4.1-nano (1M)", 1047576), 20 | GPT_5("gpt-5", "GPT-5", 400_000), 21 | GPT_5_MINI("gpt-5-mini", "GPT-5-mini", 400_000), 22 | GPT_5_CODEX("gpt-5-codex", "GPT-5 Codex", 400_000), 23 | O_1_MINI("o1-mini", "o1-mini", 128000), 24 | O_1_PREVIEW("o1-preview", "o1-preview", 128000), 25 | O_3_MINI("o3-mini", "o3-mini", 200000), 26 | O_3("o3", "o3", 200000), 27 | O_4_MINI("o4-mini", "o4-mini", 200000); 28 | 29 | private final String code; 30 | private final String description; 31 | private final int maxTokens; 32 | 33 | OpenAIChatCompletionModel(String code, String description, int maxTokens) { 34 | this.code = code; 35 | this.description = description; 36 | this.maxTokens = maxTokens; 37 | } 38 | 39 | public String getCode() { 40 | return code; 41 | } 42 | 43 | public String getDescription() { 44 | return description; 45 | } 46 | 47 | public int getMaxTokens() { 48 | return maxTokens; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return description; 54 | } 55 | 56 | public static OpenAIChatCompletionModel findByCode(String code) { 57 | return Arrays.stream(OpenAIChatCompletionModel.values()) 58 | .filter(item -> item.getCode().equals(code)) 59 | .findFirst().orElseThrow(); 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaModel.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategies; 5 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 6 | import java.util.List; 7 | 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 10 | public class OllamaModel { 11 | 12 | private String name; 13 | private long size; 14 | private OllamaModelDetails details; 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | public long getSize() { 25 | return size; 26 | } 27 | 28 | public void setSize(long size) { 29 | this.size = size; 30 | } 31 | 32 | public OllamaModelDetails getDetails() { 33 | return details; 34 | } 35 | 36 | public void setDetails(OllamaModelDetails details) { 37 | this.details = details; 38 | } 39 | 40 | @JsonIgnoreProperties(ignoreUnknown = true) 41 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 42 | public static class OllamaModelDetails { 43 | 44 | private String format; 45 | private String family; 46 | private List families; 47 | private String parameterSize; 48 | private String quantizationLevel; 49 | 50 | public String getFormat() { 51 | return format; 52 | } 53 | 54 | public void setFormat(String format) { 55 | this.format = format; 56 | } 57 | 58 | public String getFamily() { 59 | return family; 60 | } 61 | 62 | public void setFamily(String family) { 63 | this.family = family; 64 | } 65 | 66 | public List getFamilies() { 67 | return families; 68 | } 69 | 70 | public void setFamilies(List families) { 71 | this.families = families; 72 | } 73 | 74 | public String getParameterSize() { 75 | return parameterSize; 76 | } 77 | 78 | public void setParameterSize(String parameterSize) { 79 | this.parameterSize = parameterSize; 80 | } 81 | 82 | public String getQuantizationLevel() { 83 | return quantizationLevel; 84 | } 85 | 86 | public void setQuantizationLevel(String quantizationLevel) { 87 | this.quantizationLevel = quantizationLevel; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/embedding/GoogleEmbeddingRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.embedding; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 5 | import ee.carlrobert.llm.client.google.completion.GoogleCompletionContent; 6 | import java.util.List; 7 | 8 | @JsonInclude(Include.NON_NULL) 9 | public class GoogleEmbeddingRequest { 10 | 11 | private final GoogleCompletionContent content; 12 | private final TaskType taskType; 13 | private final String title; 14 | private final Integer outputDimensionality; 15 | 16 | public GoogleEmbeddingRequest(Builder builder) { 17 | this.content = builder.content; 18 | this.taskType = builder.taskType; 19 | this.title = builder.title; 20 | this.outputDimensionality = builder.outputDimensionality; 21 | } 22 | 23 | public GoogleCompletionContent getContent() { 24 | return content; 25 | } 26 | 27 | public TaskType getTaskType() { 28 | return taskType; 29 | } 30 | 31 | public String getTitle() { 32 | return title; 33 | } 34 | 35 | public Integer getOutputDimensionality() { 36 | return outputDimensionality; 37 | } 38 | 39 | /** 40 | * TaskType. 41 | */ 42 | public enum TaskType { 43 | TASK_TYPE_UNSPECIFIED, 44 | RETRIEVAL_QUERY, 45 | RETRIEVAL_DOCUMENT, 46 | SEMANTIC_SIMILARITY, 47 | CLASSIFICATION, 48 | CLUSTERING, 49 | QUESTION_ANSWERING, 50 | FACT_VERIFICATION 51 | } 52 | 53 | public static class Builder { 54 | 55 | private GoogleCompletionContent content; 56 | private TaskType taskType = TaskType.RETRIEVAL_DOCUMENT; // Set default value 57 | private String title; 58 | private Integer outputDimensionality; 59 | 60 | public Builder(GoogleCompletionContent content) { 61 | this.content = content; 62 | } 63 | 64 | public Builder taskType(TaskType taskType) { 65 | this.taskType = taskType; 66 | return this; 67 | } 68 | 69 | public Builder title(String title) { 70 | this.title = title; 71 | return this; 72 | } 73 | 74 | public Builder outputDimensionality(int outputDimensionality) { 75 | this.outputDimensionality = outputDimensionality; 76 | return this; 77 | } 78 | 79 | public GoogleEmbeddingRequest build() { 80 | return new GoogleEmbeddingRequest(this); 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/OpenAIChatCompletionEventSourceListener.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion; 2 | 3 | import static ee.carlrobert.llm.client.DeserializationUtil.OBJECT_MAPPER; 4 | 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import ee.carlrobert.llm.client.openai.completion.response.OpenAIChatCompletionResponse; 7 | import ee.carlrobert.llm.completion.CompletionEventListener; 8 | import ee.carlrobert.llm.completion.CompletionEventSourceListener; 9 | 10 | public class OpenAIChatCompletionEventSourceListener extends CompletionEventSourceListener { 11 | 12 | public OpenAIChatCompletionEventSourceListener(CompletionEventListener listener) { 13 | super(listener); 14 | } 15 | 16 | /** 17 | * Content of the first choice. 18 | *
    19 | *
  • Search all choices which are not null
  • 20 | *
  • Search all deltas which are not null
  • 21 | *
  • Use first content which is not null or blank (whitespace)
  • 22 | *
  • Otherwise use "" (empty string) if no match can be found
  • 23 | *
24 | * 25 | * @return First non-blank content which can be found, otherwise {@code ""} 26 | */ 27 | protected String getMessage(String data) throws JsonProcessingException { 28 | var response = OBJECT_MAPPER.readValue(data, OpenAIChatCompletionResponse.class); 29 | var choices = response.getChoices(); 30 | 31 | if (choices == null || choices.isEmpty()) { 32 | return ""; 33 | } 34 | 35 | var firstChoice = choices.get(0); 36 | if (firstChoice == null || firstChoice.getDelta() == null) { 37 | return ""; 38 | } 39 | 40 | var delta = firstChoice.getDelta(); 41 | if (delta.getToolCalls() != null && !delta.getToolCalls().isEmpty()) { 42 | var toolCalls = delta.getToolCalls(); 43 | if (toolCalls != null && !toolCalls.isEmpty()) { 44 | for (var toolCall : toolCalls) { 45 | if (toolCall != null && toolCall.getFunction() != null) { 46 | listener.onToolCall(toolCall); 47 | } 48 | } 49 | } 50 | } 51 | 52 | var content = firstChoice.getDelta().getContent(); 53 | if (content == null) { 54 | return ""; 55 | } 56 | 57 | return content; 58 | } 59 | 60 | @Override 61 | protected ErrorDetails getErrorDetails(String data) throws JsonProcessingException { 62 | return OBJECT_MAPPER.readValue(data, ApiResponseError.class).getError(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAIImageUrl.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonEnumDefaultValue; 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonValue; 7 | import java.util.Base64; 8 | 9 | /** 10 | * Messages with image content are supported by OpenAIs Vision models. 11 | */ 12 | @JsonInclude(JsonInclude.Include.NON_NULL) 13 | public class OpenAIImageUrl { 14 | 15 | private String url; 16 | 17 | private ImageDetail detail; 18 | 19 | public OpenAIImageUrl(String mediaType, byte[] imageData, ImageDetail detail) { 20 | this.setImageUrl(mediaType, imageData); 21 | this.detail = detail; 22 | } 23 | 24 | public OpenAIImageUrl(String mediaType, byte[] imageData) { 25 | this.setImageUrl(mediaType, imageData); 26 | } 27 | 28 | public OpenAIImageUrl(String imageUrl, ImageDetail detail) { 29 | this.url = imageUrl; 30 | this.detail = detail; 31 | } 32 | 33 | public OpenAIImageUrl(String imageUrl) { 34 | this.url = imageUrl; 35 | } 36 | 37 | public OpenAIImageUrl() { 38 | } 39 | 40 | public ImageDetail getDetail() { 41 | return detail; 42 | } 43 | 44 | public void setDetail(ImageDetail detail) { 45 | this.detail = detail; 46 | } 47 | 48 | 49 | public String getUrl() { 50 | return url; 51 | } 52 | 53 | /** 54 | * Sets the URL for the image. 55 | * This can be any publicly accessible URL. 56 | * 57 | * @param url URL to the image 58 | */ 59 | public void setUrl(String url) { 60 | this.url = url; 61 | } 62 | 63 | /** 64 | * Sets the url in a way so that data is directly uploaded to OpenAI. 65 | * 66 | * @param mediaType media type of the image (e.g. "image/jpeg") 67 | * @param imageData byte data of the image 68 | */ 69 | @JsonIgnore 70 | public void setImageUrl(String mediaType, byte[] imageData) { 71 | this.url = "data:" + mediaType + ";base64," 72 | + Base64.getEncoder().encodeToString(imageData); 73 | } 74 | 75 | public enum ImageDetail { 76 | HIGH("high"), 77 | LOW("low"), 78 | @JsonEnumDefaultValue 79 | AUTO("auto"); 80 | private final String detail; 81 | 82 | ImageDetail(String detail) { 83 | this.detail = detail; 84 | } 85 | 86 | @JsonValue 87 | public String getDetail() { 88 | return this.detail; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/completion/GoogleGenerationConfig.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.completion; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Gemini API 7 | * GenerationConfig. 8 | */ 9 | public class GoogleGenerationConfig { 10 | 11 | private final List stopSequences; 12 | private final int candidateCount; 13 | private final double temperature; 14 | private final int maxOutputTokens; 15 | private final double topP; 16 | private final int topK; 17 | 18 | public GoogleGenerationConfig(Builder builder) { 19 | this.stopSequences = builder.stopSequences; 20 | this.candidateCount = builder.candidateCount; 21 | this.temperature = builder.temperature; 22 | this.maxOutputTokens = builder.maxOutputTokens; 23 | this.topP = builder.topP; 24 | this.topK = builder.topK; 25 | } 26 | 27 | public List getStopSequences() { 28 | return stopSequences; 29 | } 30 | 31 | public int getCandidateCount() { 32 | return candidateCount; 33 | } 34 | 35 | public double getTemperature() { 36 | return temperature; 37 | } 38 | 39 | public int getMaxOutputTokens() { 40 | return maxOutputTokens; 41 | } 42 | 43 | public double getTopP() { 44 | return topP; 45 | } 46 | 47 | public int getTopK() { 48 | return topK; 49 | } 50 | 51 | public static class Builder { 52 | 53 | private List stopSequences; 54 | private int candidateCount = 1; 55 | private double temperature = 0.9; 56 | private int maxOutputTokens = 256; 57 | private double topP = 0.9; 58 | private int topK = 40; 59 | 60 | public Builder stopSequences(List stopSequences) { 61 | this.stopSequences = stopSequences; 62 | return this; 63 | } 64 | 65 | public Builder candidateCount(int candidateCount) { 66 | this.candidateCount = candidateCount; 67 | return this; 68 | } 69 | 70 | public Builder temperature(double temperature) { 71 | this.temperature = temperature; 72 | return this; 73 | } 74 | 75 | public Builder maxOutputTokens(int maxOutputTokens) { 76 | this.maxOutputTokens = maxOutputTokens; 77 | return this; 78 | } 79 | 80 | public Builder topP(double topP) { 81 | this.topP = topP; 82 | return this; 83 | } 84 | 85 | public Builder topK(int topK) { 86 | this.topK = topK; 87 | return this; 88 | } 89 | 90 | public GoogleGenerationConfig build() { 91 | return new GoogleGenerationConfig(this); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/models/GoogleModel.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.models; 2 | 3 | import java.util.Arrays; 4 | 5 | public enum GoogleModel { 6 | GEMINI_1_0_PRO_VISION_LATEST("gemini-1.0-pro-vision-latest", "Gemini 1.0 Pro Vision Latest (16k)", 7 | 12288 + 4096), 8 | GEMINI_1_5_PRO("gemini-1.5-pro", "Gemini 1.5 Pro", 2000000 + 8192), 9 | GEMINI_2_0_FLASH("gemini-2.0-flash", "Gemini 2.0 Flash", 2000000 + 8192), 10 | GEMINI_2_5_FLASH("gemini-2.5-flash", "Gemini 2.5 Flash", 1048576), 11 | GEMINI_2_0_FLASH_THINKING_EXP("gemini-2.0-flash-thinking-exp-01-21", 12 | "Gemini 2.0 Flash Thinking (Experimental)", 2000000 + 8192, true), 13 | GEMINI_2_0_PRO_EXP("gemini-2.0-pro-exp-02-05", 14 | "Gemini 2.0 Pro (Experimental)", 2000000 + 8192, true), 15 | GEMINI_2_5_PRO_PREVIEW("gemini-2.5-pro-preview-06-05", 16 | "Gemini 2.5 Pro (Preview)", 1048576, true), 17 | GEMINI_2_5_PRO("gemini-2.5-pro", 18 | "Gemini 2.5 Pro", 1048576), 19 | GEMINI_2_5_FLASH_PREVIEW("gemini-2.5-flash-preview-05-20", 20 | "Gemini 2.5 Flash (Preview)", 1048576, true), 21 | GEMINI_2_5_FLASH_LITE_PREVIEW("gemini-2.5-flash-lite-preview-06-17", 22 | "Gemini 2.5 Flash Lite (Preview)", 1000000, true), 23 | GEMINI_PRO_VISION("gemini-pro-vision", "Gemini Pro Vision (16k)", 12288 + 4096), 24 | EMBEDDING_001("embedding-001", "Embedding 001 (2k)", 2048 + 1), 25 | TEXT_EMBEDDING_004("text-embedding-004", "Text Embedding (2k)", 2048 + 1); 26 | 27 | private final String code; 28 | private final String description; 29 | private final int maxTokens; 30 | private final boolean experimental; 31 | 32 | GoogleModel(String code, String description, int maxTokens) { 33 | this(code, description, maxTokens, false); 34 | } 35 | 36 | GoogleModel(String code, String description, int maxTokens, boolean experimental) { 37 | this.code = code; 38 | this.description = description; 39 | this.maxTokens = maxTokens; 40 | this.experimental = experimental; 41 | } 42 | 43 | public String getCode() { 44 | return code; 45 | } 46 | 47 | public String getDescription() { 48 | return description; 49 | } 50 | 51 | public int getMaxTokens() { 52 | return maxTokens; 53 | } 54 | 55 | public boolean isExperimental() { 56 | return experimental; 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return description; 62 | } 63 | 64 | public static GoogleModel findByCode(String code) { 65 | return Arrays.stream(GoogleModel.values()) 66 | .filter(item -> item.getCode().equals(code)) 67 | .findFirst() 68 | .orElse(null); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/completion/GoogleContentPart.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 5 | import java.util.Base64; 6 | import java.util.Base64.Encoder; 7 | 8 | /** 9 | * See Part. 10 | */ 11 | @JsonInclude(Include.NON_NULL) 12 | public class GoogleContentPart { 13 | 14 | private String text; 15 | private Blob inlineData; 16 | private Boolean thought; 17 | 18 | public GoogleContentPart() { 19 | } 20 | 21 | public GoogleContentPart(String text) { 22 | this(text, null, null); 23 | } 24 | 25 | public GoogleContentPart(String text, Blob inlineData) { 26 | this(text, inlineData, null); 27 | } 28 | 29 | public GoogleContentPart(String text, Blob inlineData, Boolean thought) { 30 | this.text = text; 31 | this.inlineData = inlineData; 32 | this.thought = thought; 33 | } 34 | 35 | public String getText() { 36 | return text; 37 | } 38 | 39 | public void setText(String text) { 40 | this.text = text; 41 | } 42 | 43 | public Blob getInlineData() { 44 | return inlineData; 45 | } 46 | 47 | public void setInlineData(Blob inlineData) { 48 | this.inlineData = inlineData; 49 | } 50 | 51 | public Boolean getThought() { 52 | return thought; 53 | } 54 | 55 | public void setThought(Boolean thought) { 56 | this.thought = thought; 57 | } 58 | 59 | /** 60 | * Blob. 61 | */ 62 | public static class Blob { 63 | 64 | public static final Encoder ENCODER = Base64.getEncoder(); 65 | 66 | private String mimeType; 67 | 68 | /** 69 | * base64 encoded. 70 | */ 71 | private String data; 72 | 73 | public Blob() { 74 | } 75 | 76 | public Blob(String mimeType, byte[] data) { 77 | this.mimeType = mimeType; 78 | this.data = ENCODER.encodeToString(data); 79 | } 80 | 81 | public Blob(String mimeType, String base64EncodedData) { 82 | this.mimeType = mimeType; 83 | this.data = base64EncodedData; 84 | } 85 | 86 | public String getMimeType() { 87 | return mimeType; 88 | } 89 | 90 | public void setMimeType(String mimeType) { 91 | this.mimeType = mimeType; 92 | } 93 | 94 | public String getData() { 95 | return data; 96 | } 97 | 98 | public void setData(String data) { 99 | this.data = data; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # CodeGPT - LLM Client 3 | A user-friendly Java HTTP client, providing access to the large language model (LLM) APIs and services. 4 | 5 | [![Contributions welcome][contributions-welcome-svg]][contributions-welcome] 6 | [![Maven][maven-shield]][maven-url] 7 | 8 | ## Installation 9 | To use the package, you need to use following Maven dependency: 10 | 11 | ```xml 12 | 13 | ee.carlrobert 14 | llm-client 15 | 0.8.57 16 | 17 | ``` 18 | Gradle dependency: 19 | ```kts 20 | dependencies { 21 | implementation("ee.carlrobert:llm-client:0.8.57") 22 | } 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Chat Completion SSE 28 | ```java 29 | OpenAIClient client = new OpenAIClient.Builder(System.getenv("OPENAI_API_KEY")) 30 | .setOrganization("MY_ORGANIZATION") 31 | .build(); 32 | 33 | EventSource call = client.getChatCompletionAsync( 34 | new OpenAIChatCompletionRequest.Builder(List.of(new OpenAIChatCompletionStandardMessage("user", prompt))) 35 | .setModel(OpenAIChatCompletionModel.GPT_4) 36 | .setTemperature(0.1) 37 | .build(), 38 | new CompletionEventListener(){ 39 | @Override 40 | public void onMessage(String message, EventSource eventSource) { 41 | System.out.println(message); 42 | } 43 | }); 44 | 45 | call.cancel(); 46 | ``` 47 | 48 | ## Contributing 49 | 50 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 51 | 52 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 53 | 54 | 1. Fork the Project 55 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 56 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 57 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 58 | 5. Open a Pull Request 59 | 60 | ## License 61 | This is an unofficial OpenAI library and is not associated with or endorsed by OpenAI. 62 | 63 | MIT © [Carl-Robert Linnupuu][portfolio] 64 | 65 | 66 | 67 | 68 | 69 | [contributions-welcome-svg]: http://img.shields.io/badge/contributions-welcome-brightgreen 70 | [contributions-welcome]: https://github.com/JetBrains/ideavim/blob/master/CONTRIBUTING.md 71 | [maven-shield]: https://img.shields.io/maven-central/v/ee.carlrobert/llm-client 72 | [maven-url]: https://central.sonatype.com/namespace/ee.carlrobert 73 | [portfolio]: https://carlrobert.ee 74 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/request/OllamaChatCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import ee.carlrobert.llm.client.ollama.completion.response.OllamaResponseFormat; 5 | import ee.carlrobert.llm.completion.CompletionRequest; 6 | import java.util.List; 7 | 8 | /* 9 | * See ollama/api 10 | */ 11 | @JsonInclude(JsonInclude.Include.NON_NULL) 12 | public class OllamaChatCompletionRequest implements CompletionRequest { 13 | 14 | private final String model; 15 | private final List messages; 16 | private final OllamaResponseFormat format; 17 | private final OllamaParameters options; 18 | private final Boolean stream; 19 | private final String keepAlive; 20 | 21 | public OllamaChatCompletionRequest(Builder builder) { 22 | this.model = builder.model; 23 | this.messages = builder.messages; 24 | this.format = builder.format; 25 | this.options = builder.options; 26 | this.stream = builder.stream; 27 | this.keepAlive = builder.keepAlive; 28 | } 29 | 30 | public String getModel() { 31 | return model; 32 | } 33 | 34 | public List getMessages() { 35 | return messages; 36 | } 37 | 38 | public OllamaResponseFormat getFormat() { 39 | return format; 40 | } 41 | 42 | public OllamaParameters getOptions() { 43 | return options; 44 | } 45 | 46 | public Boolean getStream() { 47 | return stream; 48 | } 49 | 50 | public String getKeepAlive() { 51 | return keepAlive; 52 | } 53 | 54 | public static class Builder { 55 | 56 | private final String model; 57 | private final List messages; 58 | 59 | private OllamaResponseFormat format = null; 60 | private OllamaParameters options = null; 61 | private Boolean stream = null; 62 | private String keepAlive = null; 63 | 64 | public Builder(String model, List messages) { 65 | this.model = model; 66 | this.messages = messages; 67 | } 68 | 69 | public Builder setFormat(OllamaResponseFormat format) { 70 | this.format = format; 71 | return this; 72 | } 73 | 74 | public Builder setOptions(OllamaParameters options) { 75 | this.options = options; 76 | return this; 77 | } 78 | 79 | public Builder setStream(Boolean stream) { 80 | this.stream = stream; 81 | return this; 82 | } 83 | 84 | public Builder setKeepAlive(String keepAlive) { 85 | this.keepAlive = keepAlive; 86 | return this; 87 | } 88 | 89 | public OllamaChatCompletionRequest build() { 90 | return new OllamaChatCompletionRequest(this); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouCompletionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import ee.carlrobert.llm.completion.CompletionResponse; 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | @JsonIgnoreProperties(ignoreUnknown = true) 11 | public class YouCompletionResponse implements CompletionResponse { 12 | 13 | private final String chatToken; 14 | private final String altChatToken; 15 | private final String section; 16 | private final boolean sectionDone; 17 | private final YouSourceResult sourceResult; 18 | 19 | private final List serpResults; 20 | private final List relatedSearches; 21 | 22 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 23 | public YouCompletionResponse( 24 | @JsonProperty("youChatToken") String chatToken, 25 | @JsonProperty("youChatSerpResults") List serpResults, 26 | @JsonProperty("t") String altChatToken, 27 | @JsonProperty("msg") String section, 28 | @JsonProperty("done") boolean sectionDone, 29 | @JsonProperty("relatedSearches") List relatedSearches, 30 | @JsonProperty("search") YouThirdPartySearchResult thirdPartySearchResult, 31 | @JsonProperty("source") YouSourceResult sourceResult) { 32 | this.chatToken = chatToken; 33 | this.altChatToken = altChatToken; 34 | this.section = section; 35 | this.sectionDone = sectionDone; 36 | this.relatedSearches = relatedSearches; 37 | this.sourceResult = sourceResult; 38 | 39 | if (serpResults != null && !serpResults.isEmpty()) { 40 | this.serpResults = serpResults; 41 | } else if (thirdPartySearchResult != null && thirdPartySearchResult.hasSearchResults()) { 42 | this.serpResults = thirdPartySearchResult.getThirdPartySearchResults(); 43 | } else { 44 | this.serpResults = null; 45 | } 46 | } 47 | 48 | public String getChatToken() { 49 | if (chatToken != null) { 50 | return chatToken; 51 | } 52 | 53 | if (altChatToken != null) { 54 | return altChatToken; 55 | } 56 | 57 | if (section != null && !sectionDone) { 58 | return "\n**" + section + "**\n\n"; 59 | } 60 | 61 | if (relatedSearches != null) { 62 | return "\n**Related searches**\n\n" + relatedSearches.stream() 63 | .map(element -> "* " + element + "\n") 64 | .collect(Collectors.joining()); 65 | } 66 | 67 | if (sourceResult != null && sourceResult.isValid()) { 68 | return "* " + sourceResult.toString() + "\n"; 69 | } 70 | 71 | return null; 72 | } 73 | 74 | public List getSerpResults() { 75 | return serpResults; 76 | } 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/imagegen/response/OpenAiImageGenerationResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.imagegen.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 6 | import com.fasterxml.jackson.annotation.JsonProperty; 7 | import ee.carlrobert.llm.client.openai.completion.ErrorDetails; 8 | import ee.carlrobert.llm.imagegen.ImageGenerationResponse; 9 | import java.util.Base64; 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | @JsonIgnoreProperties(ignoreUnknown = true) 14 | public class OpenAiImageGenerationResponse implements ImageGenerationResponse { 15 | 16 | @JsonProperty("data") 17 | private final List data; 18 | 19 | @JsonIgnore 20 | private final Date created; 21 | 22 | @JsonProperty("error") 23 | private final ErrorDetails error; 24 | 25 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 26 | public OpenAiImageGenerationResponse( 27 | @JsonProperty("data") List data, 28 | @JsonProperty("created") Long created, 29 | @JsonProperty("error") ErrorDetails error) { 30 | this.data = data; 31 | this.created = 32 | created == null ? null : new Date(created * 1000L); // date is given as unix timestamp 33 | this.error = error; 34 | } 35 | 36 | public List getData() { 37 | return data; 38 | } 39 | 40 | public ErrorDetails getError() { 41 | return error; 42 | } 43 | 44 | @JsonIgnore 45 | public Date getCreated() { 46 | return created; 47 | } 48 | 49 | @JsonProperty("created") 50 | public Long getCreatedAsLong() { 51 | if (created == null) { 52 | return null; 53 | } 54 | return created.getTime() / 1000L; 55 | } 56 | 57 | @JsonIgnoreProperties(ignoreUnknown = true) 58 | public static class OpenAiImageGenerationResponseData implements ImageGenerationResponse { 59 | 60 | @JsonProperty("url") 61 | private final String url; 62 | 63 | @JsonIgnore 64 | private final byte[] imageData; 65 | 66 | @JsonProperty("revised_prompt") 67 | private final String revisedPrompt; 68 | 69 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 70 | public OpenAiImageGenerationResponseData( 71 | @JsonProperty("url") String url, 72 | @JsonProperty("b64_json") String base64json, 73 | @JsonProperty("revised_prompt") String revisedPrompt) { 74 | this.url = url; 75 | this.imageData = base64json == null ? null : Base64.getDecoder().decode(base64json); 76 | this.revisedPrompt = revisedPrompt; 77 | } 78 | 79 | public String getUrl() { 80 | return url; 81 | } 82 | 83 | @JsonIgnore 84 | public byte[] getImageData() { 85 | return this.imageData; 86 | } 87 | 88 | @JsonProperty("b64_json") 89 | public String getImageDataBase64() { 90 | return this.imageData == null ? null : Base64.getEncoder().encodeToString(this.imageData); 91 | } 92 | 93 | public String getRevisedPrompt() { 94 | return revisedPrompt; 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/response/OpenAIResponseTextEventSourceListener.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.response; 2 | 3 | import static ee.carlrobert.llm.client.DeserializationUtil.OBJECT_MAPPER; 4 | 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import ee.carlrobert.llm.client.openai.completion.ApiResponseError; 8 | import ee.carlrobert.llm.client.openai.completion.ErrorDetails; 9 | import ee.carlrobert.llm.client.openai.response.response.OpenAIResponseCompletionResponse; 10 | import ee.carlrobert.llm.completion.CompletionEventListener; 11 | import ee.carlrobert.llm.completion.CompletionEventSourceListener; 12 | import java.util.List; 13 | 14 | public class OpenAIResponseTextEventSourceListener extends CompletionEventSourceListener { 15 | 16 | public OpenAIResponseTextEventSourceListener(CompletionEventListener listener) { 17 | super(listener); 18 | } 19 | 20 | @Override 21 | protected String getMessage(String data) throws JsonProcessingException { 22 | JsonNode root = OBJECT_MAPPER.readTree(data); 23 | if (root != null && root.has("type")) { 24 | JsonNode deltaNode = root.get("delta"); 25 | if (deltaNode != null && deltaNode.isTextual()) { 26 | return deltaNode.asText(); 27 | } 28 | 29 | if (root.has("response") && root.get("response").isObject()) { 30 | OpenAIResponseCompletionResponse resp = 31 | OBJECT_MAPPER.treeToValue(root.get("response"), OpenAIResponseCompletionResponse.class); 32 | return extractFirstTextContent(resp); 33 | } 34 | return null; 35 | } 36 | 37 | OpenAIResponseCompletionResponse resp = 38 | OBJECT_MAPPER.readValue(data, OpenAIResponseCompletionResponse.class); 39 | return extractFirstTextContent(resp); 40 | } 41 | 42 | private String extractFirstTextContent(OpenAIResponseCompletionResponse resp) { 43 | if (resp == null) { 44 | return null; 45 | } 46 | List output = resp.getOutput(); 47 | if (output == null || output.isEmpty()) { 48 | return null; 49 | } 50 | var first = output.get(0); 51 | if (first == null) { 52 | return null; 53 | } 54 | var content = first.getContent(); 55 | if (content instanceof String) { 56 | return (String) content; 57 | } 58 | try { 59 | JsonNode node = OBJECT_MAPPER.valueToTree(content); 60 | if (node.isArray()) { 61 | StringBuilder sb = new StringBuilder(); 62 | for (JsonNode part : node) { 63 | if (part.has("type") && "output_text".equals(part.get("type").asText())) { 64 | JsonNode text = part.get("text"); 65 | if (text != null && text.isTextual()) { 66 | sb.append(text.asText()); 67 | } 68 | } 69 | } 70 | return sb.length() == 0 ? null : sb.toString(); 71 | } 72 | } catch (Exception e) { 73 | return null; 74 | } 75 | return null; 76 | } 77 | 78 | @Override 79 | protected ErrorDetails getErrorDetails(String data) throws JsonProcessingException { 80 | return OBJECT_MAPPER.readValue(data, ApiResponseError.class).getError(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import ee.carlrobert.llm.completion.CompletionRequest; 5 | import java.util.List; 6 | 7 | public class ClaudeCompletionRequest implements CompletionRequest { 8 | 9 | private String model; 10 | private String system; 11 | private List messages; 12 | @JsonProperty("max_tokens") 13 | private int maxTokens; 14 | private boolean stream; 15 | private Double temperature = 0.0; 16 | @JsonProperty("top_k") 17 | private Integer topK; 18 | @JsonProperty("top_p") 19 | private Integer topP; 20 | @JsonProperty("stop_sequences") 21 | private List stopSequences; 22 | private ClaudeCompletionRequestThinking thinking; 23 | private List tools; 24 | @JsonProperty("tool_choice") 25 | private ClaudeToolChoice toolChoice; 26 | 27 | public String getModel() { 28 | return model; 29 | } 30 | 31 | public void setModel(String model) { 32 | this.model = model; 33 | } 34 | 35 | public String getSystem() { 36 | return system; 37 | } 38 | 39 | public void setSystem(String system) { 40 | this.system = system; 41 | } 42 | 43 | public List getMessages() { 44 | return messages; 45 | } 46 | 47 | public void setMessages(List messages) { 48 | this.messages = messages; 49 | } 50 | 51 | public int getMaxTokens() { 52 | return maxTokens; 53 | } 54 | 55 | public void setMaxTokens(int maxTokens) { 56 | this.maxTokens = maxTokens; 57 | } 58 | 59 | public boolean isStream() { 60 | return stream; 61 | } 62 | 63 | public void setStream(boolean stream) { 64 | this.stream = stream; 65 | } 66 | 67 | public Double getTemperature() { 68 | return temperature; 69 | } 70 | 71 | public void setTemperature(Double temperature) { 72 | this.temperature = temperature; 73 | } 74 | 75 | public Integer getTopK() { 76 | return topK; 77 | } 78 | 79 | public void setTopK(Integer topK) { 80 | this.topK = topK; 81 | } 82 | 83 | public Integer getTopP() { 84 | return topP; 85 | } 86 | 87 | public void setTopP(Integer topP) { 88 | this.topP = topP; 89 | } 90 | 91 | public List getStopSequences() { 92 | return stopSequences; 93 | } 94 | 95 | public void setStopSequences(List stopSequences) { 96 | this.stopSequences = stopSequences; 97 | } 98 | 99 | public ClaudeCompletionRequestThinking getThinking() { 100 | return thinking; 101 | } 102 | 103 | public void setThinking(ClaudeCompletionRequestThinking thinking) { 104 | this.thinking = thinking; 105 | } 106 | 107 | public List getTools() { 108 | return tools; 109 | } 110 | 111 | public void setTools(List tools) { 112 | this.tools = tools; 113 | } 114 | 115 | public ClaudeToolChoice getToolChoice() { 116 | return toolChoice; 117 | } 118 | 119 | public void setToolChoice(ClaudeToolChoice toolChoice) { 120 | this.toolChoice = toolChoice; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/llama/completion/LlamaCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.llama.completion; 2 | 3 | import ee.carlrobert.llm.completion.CompletionRequest; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | public class LlamaCompletionRequest implements CompletionRequest { 8 | 9 | private final String prompt; 10 | private final int n_predict; 11 | private final boolean stream; 12 | private final double temperature; 13 | private final int top_k; 14 | private final double top_p; 15 | private final double min_p; 16 | private final double repeat_penalty; 17 | private final List stop; 18 | 19 | public LlamaCompletionRequest(Builder builder) { 20 | this.prompt = builder.prompt; 21 | this.stream = builder.stream; 22 | this.n_predict = builder.n_predict; 23 | this.temperature = builder.temperature; 24 | this.top_k = builder.top_k; 25 | this.top_p = builder.top_p; 26 | this.min_p = builder.min_p; 27 | this.repeat_penalty = builder.repeat_penalty; 28 | this.stop = builder.stop; 29 | } 30 | 31 | public String getPrompt() { 32 | return prompt; 33 | } 34 | 35 | public Boolean isStream() { 36 | return stream; 37 | } 38 | 39 | public int getN_predict() { 40 | return n_predict; 41 | } 42 | 43 | public double getTemperature() { 44 | return temperature; 45 | } 46 | 47 | public int getTop_k() { 48 | return top_k; 49 | } 50 | 51 | public double getTop_p() { 52 | return top_p; 53 | } 54 | 55 | public double getMin_p() { 56 | return min_p; 57 | } 58 | 59 | public double getRepeat_penalty() { 60 | return repeat_penalty; 61 | } 62 | 63 | public List getStop() { 64 | return stop; 65 | } 66 | 67 | public static class Builder { 68 | 69 | private final String prompt; 70 | private boolean stream = true; 71 | private int n_predict = 256; 72 | private double temperature = 0.1; 73 | private int top_k = 40; 74 | private double top_p = 0.9; 75 | private double min_p = 0.05; 76 | private double repeat_penalty = 1.1; 77 | private List stop = new ArrayList<>(); 78 | 79 | public Builder(String prompt) { 80 | this.prompt = prompt; 81 | } 82 | 83 | public Builder setStream(boolean stream) { 84 | this.stream = stream; 85 | return this; 86 | } 87 | 88 | public Builder setN_predict(int n_predict) { 89 | this.n_predict = n_predict; 90 | return this; 91 | } 92 | 93 | public Builder setTemperature(double temperature) { 94 | this.temperature = temperature; 95 | return this; 96 | } 97 | 98 | public Builder setTop_k(int top_k) { 99 | this.top_k = top_k; 100 | return this; 101 | } 102 | 103 | public Builder setTop_p(double top_p) { 104 | this.top_p = top_p; 105 | return this; 106 | } 107 | 108 | public Builder setMin_p(double min_p) { 109 | this.min_p = min_p; 110 | return this; 111 | } 112 | 113 | public Builder setRepeat_penalty(double repeat_penalty) { 114 | this.repeat_penalty = repeat_penalty; 115 | return this; 116 | } 117 | 118 | public Builder setStop(List stop) { 119 | this.stop = stop; 120 | return this; 121 | } 122 | public LlamaCompletionRequest build() { 123 | return new LlamaCompletionRequest(this); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/models/GoogleModelsResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.models; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import java.util.List; 5 | 6 | @JsonIgnoreProperties(ignoreUnknown = true) 7 | public class GoogleModelsResponse { 8 | 9 | private List models; 10 | private String nextPageToken; 11 | 12 | public List getModels() { 13 | return models; 14 | } 15 | 16 | public void setModels(List models) { 17 | this.models = models; 18 | } 19 | 20 | public String getNextPageToken() { 21 | return nextPageToken; 22 | } 23 | 24 | public void setNextPageToken(String nextPageToken) { 25 | this.nextPageToken = nextPageToken; 26 | } 27 | 28 | public static class GeminiModelDetails { 29 | 30 | private String name; 31 | private String baseModelId; 32 | private String version; 33 | private String displayName; 34 | private String description; 35 | private int inputTokenLimit; 36 | private int outputTokenLimit; 37 | private List supportedGenerationMethods; 38 | private double temperature; 39 | private double topP; 40 | private int topK; 41 | 42 | public String getName() { 43 | return name; 44 | } 45 | 46 | public void setName(String name) { 47 | this.name = name; 48 | } 49 | 50 | public String getBaseModelId() { 51 | return baseModelId; 52 | } 53 | 54 | public void setBaseModelId(String baseModelId) { 55 | this.baseModelId = baseModelId; 56 | } 57 | 58 | public String getVersion() { 59 | return version; 60 | } 61 | 62 | public void setVersion(String version) { 63 | this.version = version; 64 | } 65 | 66 | public String getDisplayName() { 67 | return displayName; 68 | } 69 | 70 | public void setDisplayName(String displayName) { 71 | this.displayName = displayName; 72 | } 73 | 74 | public String getDescription() { 75 | return description; 76 | } 77 | 78 | public void setDescription(String description) { 79 | this.description = description; 80 | } 81 | 82 | public int getInputTokenLimit() { 83 | return inputTokenLimit; 84 | } 85 | 86 | public void setInputTokenLimit(int inputTokenLimit) { 87 | this.inputTokenLimit = inputTokenLimit; 88 | } 89 | 90 | public int getOutputTokenLimit() { 91 | return outputTokenLimit; 92 | } 93 | 94 | public void setOutputTokenLimit(int outputTokenLimit) { 95 | this.outputTokenLimit = outputTokenLimit; 96 | } 97 | 98 | public List getSupportedGenerationMethods() { 99 | return supportedGenerationMethods; 100 | } 101 | 102 | public void setSupportedGenerationMethods(List supportedGenerationMethods) { 103 | this.supportedGenerationMethods = supportedGenerationMethods; 104 | } 105 | 106 | public double getTemperature() { 107 | return temperature; 108 | } 109 | 110 | public void setTemperature(double temperature) { 111 | this.temperature = temperature; 112 | } 113 | 114 | public double getTopP() { 115 | return topP; 116 | } 117 | 118 | public void setTopP(double topP) { 119 | this.topP = topP; 120 | } 121 | 122 | public int getTopK() { 123 | return topK; 124 | } 125 | 126 | public void setTopK(int topK) { 127 | this.topK = topK; 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/you/completion/YouCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.you.completion; 2 | 3 | import ee.carlrobert.llm.completion.CompletionRequest; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public class YouCompletionRequest implements CompletionRequest { 8 | 9 | private final String prompt; 10 | private final List messages; 11 | private final UUID chatId; 12 | private final UUID userId; 13 | private final UUID queryTraceId; 14 | private final boolean useGPT4Model; 15 | 16 | private final YouCompletionMode chatMode; 17 | private final YouCompletionCustomModel customModel; 18 | 19 | public YouCompletionRequest(Builder builder) { 20 | this.prompt = builder.prompt; 21 | this.messages = builder.messages; 22 | this.chatId = builder.chatId; 23 | this.userId = builder.userId; 24 | this.queryTraceId = builder.queryTraceId; 25 | this.useGPT4Model = builder.useGPT4Model; 26 | this.chatMode = builder.chatMode; 27 | this.customModel = builder.customModel; 28 | } 29 | 30 | public String getPrompt() { 31 | return prompt; 32 | } 33 | 34 | public List getMessages() { 35 | return messages; 36 | } 37 | 38 | public UUID getChatId() { 39 | return chatId; 40 | } 41 | 42 | public UUID getUserId() { 43 | return userId; 44 | } 45 | 46 | public UUID getQueryTraceId() { 47 | return queryTraceId; 48 | } 49 | 50 | public boolean isUseGPT4Model() { 51 | return useGPT4Model; 52 | } 53 | 54 | public YouCompletionMode getChatMode() { 55 | return chatMode == null ? YouCompletionMode.DEFAULT : chatMode; 56 | } 57 | 58 | public YouCompletionCustomModel getCustomModel() { 59 | return customModel == null ? YouCompletionCustomModel.GPT_4_TURBO : customModel; 60 | } 61 | 62 | public static class Builder { 63 | 64 | private final String prompt; 65 | private List messages; 66 | private UUID chatId; 67 | private UUID userId; 68 | private UUID queryTraceId; 69 | private boolean useGPT4Model; 70 | private YouCompletionMode chatMode = YouCompletionMode.DEFAULT; 71 | private YouCompletionCustomModel customModel = YouCompletionCustomModel.GPT_4_TURBO; 72 | 73 | public Builder(String prompt) { 74 | this.prompt = prompt; 75 | } 76 | 77 | public Builder setChatHistory(List messages) { 78 | this.messages = messages; 79 | return this; 80 | } 81 | 82 | public Builder setChatId(UUID chatId) { 83 | this.chatId = chatId; 84 | return this; 85 | } 86 | 87 | public Builder setUserId(UUID userId) { 88 | this.userId = userId; 89 | return this; 90 | } 91 | 92 | public Builder setQueryTraceId(UUID queryTraceId) { 93 | this.queryTraceId = queryTraceId; 94 | return this; 95 | } 96 | 97 | public Builder setUseGPT4Model(boolean useGPT4Model) { 98 | this.useGPT4Model = useGPT4Model; 99 | return this; 100 | } 101 | 102 | public Builder setChatMode(YouCompletionMode chatMode) { 103 | this.chatMode = chatMode; 104 | return this; 105 | } 106 | 107 | public Builder setCustomModel(YouCompletionCustomModel customModel) { 108 | this.customModel = customModel; 109 | return this; 110 | } 111 | 112 | public YouCompletionRequest build() { 113 | return new YouCompletionRequest(this); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/completion/ClaudeTool.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | 7 | /** 8 | * Represents a tool definition for Claude completions. 9 | * Tools allow the model to call external functions during the completion process. 10 | */ 11 | public class ClaudeTool { 12 | private String name; 13 | private String description; 14 | @JsonProperty("input_schema") 15 | private Map inputSchema; 16 | 17 | /** 18 | * Default constructor for JSON deserialization. 19 | */ 20 | public ClaudeTool() { 21 | } 22 | 23 | /** 24 | * Creates a new Claude tool with the specified parameters. 25 | * 26 | * @param name The tool name (required) 27 | * @param description The tool description (required) 28 | * @param inputSchema The JSON schema for tool input parameters (required) 29 | * @throws IllegalArgumentException if any required parameter is null 30 | */ 31 | public ClaudeTool(String name, String description, Map inputSchema) { 32 | this.name = Objects.requireNonNull(name, "Tool name cannot be null"); 33 | this.description = Objects.requireNonNull(description, "Tool description cannot be null"); 34 | this.inputSchema = Objects.requireNonNull(inputSchema, "Tool input schema cannot be null"); 35 | } 36 | 37 | /** 38 | * Gets the tool name. 39 | * 40 | * @return The tool name 41 | */ 42 | public String getName() { 43 | return name; 44 | } 45 | 46 | /** 47 | * Sets the tool name. 48 | * 49 | * @param name The tool name 50 | * @throws IllegalArgumentException if name is null 51 | */ 52 | public void setName(String name) { 53 | this.name = Objects.requireNonNull(name, "Tool name cannot be null"); 54 | } 55 | 56 | /** 57 | * Gets the tool description. 58 | * 59 | * @return The tool description 60 | */ 61 | public String getDescription() { 62 | return description; 63 | } 64 | 65 | /** 66 | * Sets the tool description. 67 | * 68 | * @param description The tool description 69 | * @throws IllegalArgumentException if description is null 70 | */ 71 | public void setDescription(String description) { 72 | this.description = Objects.requireNonNull(description, "Tool description cannot be null"); 73 | } 74 | 75 | /** 76 | * Gets the input schema for the tool. 77 | * 78 | * @return The input schema map 79 | */ 80 | public Map getInputSchema() { 81 | return inputSchema; 82 | } 83 | 84 | /** 85 | * Sets the input schema for the tool. 86 | * 87 | * @param inputSchema The input schema map 88 | * @throws IllegalArgumentException if inputSchema is null 89 | */ 90 | public void setInputSchema(Map inputSchema) { 91 | this.inputSchema = Objects.requireNonNull(inputSchema, "Tool input schema cannot be null"); 92 | } 93 | 94 | @Override 95 | public boolean equals(Object obj) { 96 | if (this == obj) { 97 | return true; 98 | } 99 | if (obj == null || getClass() != obj.getClass()) { 100 | return false; 101 | } 102 | ClaudeTool that = (ClaudeTool) obj; 103 | return Objects.equals(name, that.name) 104 | && Objects.equals(description, that.description) 105 | && Objects.equals(inputSchema, that.inputSchema); 106 | } 107 | 108 | @Override 109 | public int hashCode() { 110 | return Objects.hash(name, description, inputSchema); 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return "ClaudeTool{" 116 | + "name='" + name + '\'' 117 | + ", description='" + description + '\'' 118 | + ", inputSchema=" + inputSchema 119 | + '}'; 120 | } 121 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/openai/completion/request/OpenAITextCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.openai.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import ee.carlrobert.llm.completion.CompletionRequest; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class OpenAITextCompletionRequest implements CompletionRequest { 9 | 10 | private final String model; 11 | private final String prompt; 12 | private final String suffix; 13 | @JsonProperty("max_tokens") 14 | private final int maxTokens; 15 | private final double temperature; 16 | @JsonProperty("frequency_penalty") 17 | private final double frequencyPenalty; 18 | @JsonProperty("presence_penalty") 19 | private final double presencePenalty; 20 | private final boolean stream; 21 | private final List stop; 22 | 23 | protected OpenAITextCompletionRequest(Builder builder) { 24 | this.model = builder.model; 25 | this.prompt = builder.prompt; 26 | this.suffix = builder.suffix; 27 | this.maxTokens = builder.maxTokens; 28 | this.temperature = builder.temperature; 29 | this.frequencyPenalty = builder.frequencyPenalty; 30 | this.presencePenalty = builder.presencePenalty; 31 | this.stream = builder.stream; 32 | this.stop = builder.stop; 33 | } 34 | 35 | public int getMaxTokens() { 36 | return maxTokens; 37 | } 38 | 39 | public String getModel() { 40 | return model; 41 | } 42 | 43 | public String getPrompt() { 44 | return prompt; 45 | } 46 | 47 | public String getSuffix() { 48 | return suffix; 49 | } 50 | 51 | public double getTemperature() { 52 | return temperature; 53 | } 54 | 55 | public double getFrequencyPenalty() { 56 | return frequencyPenalty; 57 | } 58 | 59 | public double getPresencePenalty() { 60 | return presencePenalty; 61 | } 62 | 63 | public boolean isStream() { 64 | return stream; 65 | } 66 | 67 | public List getStop() { 68 | return stop; 69 | } 70 | 71 | public static class Builder { 72 | 73 | private final String prompt; 74 | 75 | private String model = "gpt-3.5-turbo-instruct"; 76 | private String suffix; 77 | private int maxTokens = 1000; 78 | private double temperature = 0.9; 79 | private double frequencyPenalty = 0; 80 | private double presencePenalty = 0.6; 81 | private boolean stream = true; 82 | private List stop = new ArrayList<>(List.of("\n\n")); 83 | 84 | public Builder(String prompt) { 85 | this.prompt = prompt; 86 | } 87 | 88 | public Builder setModel(String model) { 89 | this.model = model; 90 | return this; 91 | } 92 | 93 | public Builder setSuffix(String suffix) { 94 | this.suffix = suffix; 95 | return this; 96 | } 97 | 98 | public Builder setMaxTokens(int maxTokens) { 99 | this.maxTokens = maxTokens; 100 | return this; 101 | } 102 | 103 | public Builder setTemperature(double temperature) { 104 | this.temperature = temperature; 105 | return this; 106 | } 107 | 108 | public Builder setFrequencyPenalty(double frequencyPenalty) { 109 | this.frequencyPenalty = frequencyPenalty; 110 | return this; 111 | } 112 | 113 | public Builder setPresencePenalty(double presencePenalty) { 114 | this.presencePenalty = presencePenalty; 115 | return this; 116 | } 117 | 118 | public Builder setStream(boolean stream) { 119 | this.stream = stream; 120 | return this; 121 | } 122 | 123 | public Builder setStop(List stop) { 124 | this.stop = stop; 125 | return this; 126 | } 127 | 128 | public OpenAITextCompletionRequest build() { 129 | return new OpenAITextCompletionRequest(this); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/codegpt/request/CodeCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.codegpt.request; 2 | 3 | import ee.carlrobert.llm.completion.CompletionRequest; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public class CodeCompletionRequest implements CompletionRequest { 8 | 9 | private final String model; 10 | private final String prefix; 11 | private final String suffix; 12 | private final String fileExtension; 13 | private final String fileContent; 14 | private final int cursorOffset; 15 | private final List stop; 16 | private final UUID sessionId; 17 | private final String platformVersion; 18 | private final String pluginVersion; 19 | 20 | protected CodeCompletionRequest(Builder builder) { 21 | this.model = builder.model; 22 | this.prefix = builder.prefix; 23 | this.suffix = builder.suffix; 24 | this.fileExtension = builder.fileExtension; 25 | this.fileContent = builder.fileContent; 26 | this.cursorOffset = builder.cursorOffset; 27 | this.stop = builder.stop; 28 | this.sessionId = builder.sessionId; 29 | this.platformVersion = builder.platformVersion; 30 | this.pluginVersion = builder.pluginVersion; 31 | } 32 | 33 | public String getModel() { 34 | return model; 35 | } 36 | 37 | public String getPrefix() { 38 | return prefix; 39 | } 40 | 41 | public String getSuffix() { 42 | return suffix; 43 | } 44 | 45 | public String getFileExtension() { 46 | return fileExtension; 47 | } 48 | 49 | public String getFileContent() { 50 | return fileContent; 51 | } 52 | 53 | public int getCursorOffset() { 54 | return cursorOffset; 55 | } 56 | 57 | public List getStop() { 58 | return stop; 59 | } 60 | 61 | public UUID getSessionId() { 62 | return sessionId; 63 | } 64 | 65 | public String getPlatformVersion() { 66 | return platformVersion; 67 | } 68 | 69 | public String getPluginVersion() { 70 | return pluginVersion; 71 | } 72 | 73 | public static class Builder { 74 | 75 | private String model = "codestral"; 76 | private String prefix; 77 | private String suffix; 78 | private String fileExtension; 79 | private String fileContent; 80 | private int cursorOffset; 81 | private List stop; 82 | private UUID sessionId; 83 | private String platformVersion; 84 | private String pluginVersion; 85 | 86 | public Builder setModel(String model) { 87 | this.model = model; 88 | return this; 89 | } 90 | 91 | public Builder setPrefix(String prefix) { 92 | this.prefix = prefix; 93 | return this; 94 | } 95 | 96 | public Builder setSuffix(String suffix) { 97 | this.suffix = suffix; 98 | return this; 99 | } 100 | 101 | public Builder setFileExtension(String fileExtension) { 102 | this.fileExtension = fileExtension; 103 | return this; 104 | } 105 | 106 | public Builder setFileContent(String fileContent) { 107 | this.fileContent = fileContent; 108 | return this; 109 | } 110 | 111 | public Builder setCursorOffset(int cursorOffset) { 112 | this.cursorOffset = cursorOffset; 113 | return this; 114 | } 115 | 116 | public Builder setStop(List stop) { 117 | this.stop = stop; 118 | return this; 119 | } 120 | 121 | public Builder setSessionId(UUID sessionId) { 122 | this.sessionId = sessionId; 123 | return this; 124 | } 125 | 126 | public Builder setPluginVersion(String pluginVersion) { 127 | this.pluginVersion = pluginVersion; 128 | return this; 129 | } 130 | 131 | public Builder setPlatformVersion(String platformVersion) { 132 | this.platformVersion = platformVersion; 133 | return this; 134 | } 135 | 136 | public CodeCompletionRequest build() { 137 | return new CodeCompletionRequest(this); 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/request/OllamaCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 5 | import ee.carlrobert.llm.client.ollama.completion.response.OllamaResponseFormat; 6 | import ee.carlrobert.llm.completion.CompletionRequest; 7 | 8 | /* 9 | * See ollama/api 10 | */ 11 | @JsonInclude(Include.NON_NULL) 12 | public class OllamaCompletionRequest implements CompletionRequest { 13 | 14 | private final String model; 15 | private final String prompt; 16 | 17 | private final OllamaResponseFormat format; 18 | private final OllamaParameters options; 19 | private final String system; 20 | private final String template; 21 | private final String context; 22 | private final Boolean stream; 23 | private final Boolean raw; 24 | private final String suffix; 25 | 26 | public OllamaCompletionRequest(Builder builder) { 27 | this.prompt = builder.prompt; 28 | this.model = builder.model; 29 | this.format = builder.format; 30 | this.options = builder.options; 31 | this.system = builder.system; 32 | this.template = builder.template; 33 | this.context = builder.context; 34 | this.stream = builder.stream; 35 | this.raw = builder.raw; 36 | this.suffix = builder.suffix; 37 | } 38 | 39 | public String getModel() { 40 | return model; 41 | } 42 | 43 | public String getPrompt() { 44 | return prompt; 45 | } 46 | 47 | public OllamaResponseFormat getFormat() { 48 | return format; 49 | } 50 | 51 | public OllamaParameters getOptions() { 52 | return options; 53 | } 54 | 55 | public String getSystem() { 56 | return system; 57 | } 58 | 59 | public String getTemplate() { 60 | return template; 61 | } 62 | 63 | public String getContext() { 64 | return context; 65 | } 66 | 67 | public Boolean isStream() { 68 | return stream; 69 | } 70 | 71 | public Boolean isRaw() { 72 | return raw; 73 | } 74 | 75 | public String getSuffix() { 76 | return suffix; 77 | } 78 | 79 | public static class Builder { 80 | 81 | private final String model; 82 | private final String prompt; 83 | 84 | private OllamaResponseFormat format = null; 85 | private OllamaParameters options = null; 86 | private String system = null; 87 | private String template = null; 88 | private String context = null; 89 | private Boolean stream = null; 90 | private Boolean raw = null; 91 | private String suffix = null; 92 | 93 | public Builder(String model, String prompt) { 94 | this.model = model; 95 | this.prompt = prompt; 96 | } 97 | 98 | public Builder setFormat(OllamaResponseFormat format) { 99 | this.format = format; 100 | return Builder.this; 101 | } 102 | 103 | public Builder setOptions(OllamaParameters options) { 104 | this.options = options; 105 | return Builder.this; 106 | } 107 | 108 | public Builder setSystem(String system) { 109 | this.system = system; 110 | return Builder.this; 111 | } 112 | 113 | public Builder setTemplate(String template) { 114 | this.template = template; 115 | return Builder.this; 116 | } 117 | 118 | public Builder setContext(String context) { 119 | this.context = context; 120 | return Builder.this; 121 | } 122 | 123 | public Builder setStream(boolean stream) { 124 | this.stream = stream; 125 | return Builder.this; 126 | } 127 | 128 | public Builder setRaw(boolean raw) { 129 | this.raw = raw; 130 | return Builder.this; 131 | } 132 | 133 | public Builder setSuffix(String suffix) { 134 | this.suffix = suffix; 135 | return Builder.this; 136 | } 137 | 138 | public OllamaCompletionRequest build() { 139 | return new OllamaCompletionRequest(this); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/google/completion/GoogleCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.google.completion; 2 | 3 | import ee.carlrobert.llm.completion.CompletionRequest; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * See Request-Body. 9 | */ 10 | public class GoogleCompletionRequest implements CompletionRequest { 11 | 12 | private final List contents; 13 | private final List safetySettings; 14 | private final GoogleGenerationConfig generationConfig; 15 | private final GoogleCompletionContent systemInstruction; 16 | 17 | public GoogleCompletionRequest(Builder builder) { 18 | this.contents = builder.contents; 19 | this.safetySettings = builder.safetySettings; 20 | this.generationConfig = builder.generationConfig; 21 | this.systemInstruction = builder.systemInstruction; 22 | } 23 | 24 | public List getContents() { 25 | return contents; 26 | } 27 | 28 | public List getSafetySettings() { 29 | return safetySettings; 30 | } 31 | 32 | public GoogleGenerationConfig getGenerationConfig() { 33 | return generationConfig; 34 | } 35 | 36 | public GoogleCompletionContent getSystemInstruction() { 37 | return systemInstruction; 38 | } 39 | 40 | /** 41 | * Harm Category. 42 | */ 43 | public enum HarmCategory { 44 | HARM_CATEGORY_UNSPECIFIED, 45 | HARM_CATEGORY_DEROGATORY, 46 | HARM_CATEGORY_TOXICITY, 47 | HARM_CATEGORY_VIOLENCE, 48 | HARM_CATEGORY_SEXUAL, 49 | HARM_CATEGORY_MEDICAL, 50 | HARM_CATEGORY_DANGEROUS, 51 | HARM_CATEGORY_HARASSMENT, 52 | HARM_CATEGORY_HATE_SPEECH, 53 | HARM_CATEGORY_SEXUALLY_EXPLICIT, 54 | HARM_CATEGORY_DANGEROUS_CONTENT; 55 | } 56 | 57 | /** 58 | * Harm 59 | * Block Threshold. 60 | */ 61 | public enum HarmBlockThreshold { 62 | HARM_BLOCK_THRESHOLD_UNSPECIFIED, 63 | BLOCK_LOW_AND_ABOVE, 64 | BLOCK_MEDIUM_AND_ABOVE, 65 | BLOCK_ONLY_HIGH, 66 | BLOCK_NONE, 67 | } 68 | 69 | public static class SafetySetting { 70 | 71 | private final HarmCategory category; 72 | private final HarmBlockThreshold threshold; 73 | 74 | public SafetySetting(HarmCategory category, HarmBlockThreshold threshold) { 75 | this.category = category; 76 | this.threshold = threshold; 77 | } 78 | 79 | public HarmCategory getCategory() { 80 | return category; 81 | } 82 | 83 | public HarmBlockThreshold getThreshold() { 84 | return threshold; 85 | } 86 | } 87 | 88 | public static class Builder { 89 | 90 | private List contents; 91 | private List safetySettings = new ArrayList<>(); 92 | private GoogleGenerationConfig generationConfig = new GoogleGenerationConfig.Builder().build(); 93 | private GoogleCompletionContent systemInstruction = null; 94 | 95 | public Builder(List contents) { 96 | this.contents = contents; 97 | } 98 | 99 | public Builder safetySettings(List safetySettings) { 100 | this.safetySettings = safetySettings; 101 | return this; 102 | } 103 | 104 | public Builder generationConfig(GoogleGenerationConfig generationConfig) { 105 | this.generationConfig = generationConfig; 106 | return this; 107 | } 108 | 109 | public Builder systemInstruction(GoogleCompletionContent systemInstruction) { 110 | this.systemInstruction = systemInstruction; 111 | return this; 112 | } 113 | 114 | public Builder systemInstruction(String systemInstruction) { 115 | this.systemInstruction = new GoogleCompletionContent(List.of(systemInstruction)); 116 | return this; 117 | } 118 | 119 | public GoogleCompletionRequest build() { 120 | return new GoogleCompletionRequest(this); 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/ollama/completion/response/OllamaChatCompletionResponse.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.ollama.completion.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategies; 5 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 6 | import ee.carlrobert.llm.completion.CompletionResponse; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 11 | @JsonIgnoreProperties(ignoreUnknown = true) 12 | public class OllamaChatCompletionResponse implements CompletionResponse { 13 | 14 | private String model; 15 | private String createdAt; 16 | private OllamaChatCompletionMessageResponse message; 17 | private Boolean done; 18 | private Integer promptEvalCount; 19 | private Integer evalCount; 20 | private Long promptEvalDuration; 21 | private Long evalDuration; 22 | private Long totalDuration; 23 | private Long loadDuration; 24 | 25 | public OllamaChatCompletionResponse() { 26 | } 27 | 28 | public OllamaChatCompletionResponse(@NotNull String model, 29 | @NotNull String createdAt, 30 | @NotNull OllamaChatCompletionMessageResponse message, 31 | @NotNull Boolean done, 32 | @Nullable Integer promptEvalCount, 33 | @Nullable Integer evalCount, 34 | @Nullable Long promptEvalDuration, 35 | @Nullable Long evalDuration, 36 | @Nullable Long totalDuration, 37 | @Nullable Long loadDuration) { 38 | this.model = model; 39 | this.createdAt = createdAt; 40 | this.message = message; 41 | this.done = done; 42 | this.promptEvalCount = promptEvalCount; 43 | this.evalCount = evalCount; 44 | this.promptEvalDuration = promptEvalDuration; 45 | this.evalDuration = evalDuration; 46 | this.totalDuration = totalDuration; 47 | this.loadDuration = loadDuration; 48 | } 49 | 50 | @NotNull 51 | public String getModel() { 52 | return model; 53 | } 54 | 55 | public void setModel(@NotNull String model) { 56 | this.model = model; 57 | } 58 | 59 | @NotNull 60 | public String getCreatedAt() { 61 | return createdAt; 62 | } 63 | 64 | public void setCreatedAt(@NotNull String createdAt) { 65 | this.createdAt = createdAt; 66 | } 67 | 68 | @NotNull 69 | public OllamaChatCompletionMessageResponse getMessage() { 70 | return message; 71 | } 72 | 73 | public void setMessage(@NotNull OllamaChatCompletionMessageResponse message) { 74 | this.message = message; 75 | } 76 | 77 | @NotNull 78 | public Boolean isDone() { 79 | return done; 80 | } 81 | 82 | @Nullable 83 | public Integer getPromptEvalCount() { 84 | return promptEvalCount; 85 | } 86 | 87 | public void setPromptEvalCount(@Nullable Integer promptEvalCount) { 88 | this.promptEvalCount = promptEvalCount; 89 | } 90 | 91 | @Nullable 92 | public Integer getEvalCount() { 93 | return evalCount; 94 | } 95 | 96 | public void setEvalCount(@Nullable Integer evalCount) { 97 | this.evalCount = evalCount; 98 | } 99 | 100 | @Nullable 101 | public Long getPromptEvalDuration() { 102 | return promptEvalDuration; 103 | } 104 | 105 | public void setPromptEvalDuration(@Nullable Long promptEvalDuration) { 106 | this.promptEvalDuration = promptEvalDuration; 107 | } 108 | 109 | @Nullable 110 | public Long getEvalDuration() { 111 | return evalDuration; 112 | } 113 | 114 | public void setEvalDuration(@Nullable Long evalDuration) { 115 | this.evalDuration = evalDuration; 116 | } 117 | 118 | @Nullable 119 | public Long getTotalDuration() { 120 | return totalDuration; 121 | } 122 | 123 | public void setTotalDuration(@Nullable Long totalDuration) { 124 | this.totalDuration = totalDuration; 125 | } 126 | 127 | @Nullable 128 | public Long getLoadDuration() { 129 | return loadDuration; 130 | } 131 | 132 | public void setLoadDuration(@Nullable Long loadDuration) { 133 | this.loadDuration = loadDuration; 134 | } 135 | 136 | public void setDone(@NotNull Boolean done) { 137 | this.done = done; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/mixin/ExternalServiceTestMixin.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.mixin; 2 | 3 | 4 | import static ee.carlrobert.llm.client.mixin.ExternalService.ANTHROPIC; 5 | import static ee.carlrobert.llm.client.mixin.ExternalService.AZURE; 6 | import static ee.carlrobert.llm.client.mixin.ExternalService.CODEGPT; 7 | import static ee.carlrobert.llm.client.mixin.ExternalService.GOOGLE; 8 | import static ee.carlrobert.llm.client.mixin.ExternalService.LLAMA; 9 | import static ee.carlrobert.llm.client.mixin.ExternalService.MISTRAL; 10 | import static ee.carlrobert.llm.client.mixin.ExternalService.OLLAMA; 11 | import static ee.carlrobert.llm.client.mixin.ExternalService.OPENAI; 12 | import static ee.carlrobert.llm.client.mixin.ExternalService.YOU; 13 | import static ee.carlrobert.llm.client.mixin.ExternalServiceTestMixin.Private.externalServiceServerMap; 14 | 15 | import ee.carlrobert.llm.client.http.LocalCallbackServer; 16 | import ee.carlrobert.llm.client.http.exchange.BasicHttpExchange; 17 | import ee.carlrobert.llm.client.http.exchange.Exchange; 18 | import ee.carlrobert.llm.client.http.exchange.NdJsonStreamHttpExchange; 19 | import ee.carlrobert.llm.client.http.exchange.StreamHttpExchange; 20 | import ee.carlrobert.llm.client.http.expectation.BasicExpectation; 21 | import ee.carlrobert.llm.client.http.expectation.Expectation; 22 | import ee.carlrobert.llm.client.http.expectation.NdJsonStreamExpectation; 23 | import ee.carlrobert.llm.client.http.expectation.StreamExpectation; 24 | import java.util.Arrays; 25 | import java.util.Map; 26 | import java.util.stream.Collectors; 27 | 28 | public interface ExternalServiceTestMixin { 29 | 30 | class Private { 31 | 32 | static Map externalServiceServerMap; 33 | } 34 | 35 | static void init() { 36 | externalServiceServerMap = Arrays.stream(ExternalService.values()) 37 | .collect(Collectors.toMap( 38 | (service) -> service, 39 | (service) -> { 40 | var server = new LocalCallbackServer(service); 41 | System.setProperty( 42 | service.getUrlProperty(), 43 | "http://localhost" + ":" + server.getPort()); 44 | return server; 45 | })); 46 | } 47 | 48 | static void clearAll() { 49 | externalServiceServerMap.values().forEach(LocalCallbackServer::clear); 50 | } 51 | 52 | default void expectCodeGPT(Exchange exchange) { 53 | addExpectation(CODEGPT, exchange); 54 | } 55 | 56 | default void expectOpenAI(Exchange exchange) { 57 | addExpectation(OPENAI, exchange); 58 | } 59 | 60 | default void expectAnthropic(Exchange exchange) { 61 | addExpectation(ANTHROPIC, exchange); 62 | } 63 | 64 | default void expectAzure(Exchange exchange) { 65 | addExpectation(AZURE, exchange); 66 | } 67 | 68 | default void expectYou(Exchange exchange) { 69 | addExpectation(YOU, exchange); 70 | } 71 | 72 | default void expectLlama(Exchange exchange) { 73 | addExpectation(LLAMA, exchange); 74 | } 75 | 76 | default void expectOllama(Exchange exchange) { 77 | addExpectation(OLLAMA, exchange); 78 | } 79 | 80 | default void expectGoogle(Exchange exchange) { 81 | addExpectation(GOOGLE, exchange); 82 | } 83 | 84 | default void expectMistral(Exchange exchange) { 85 | addExpectation(MISTRAL, exchange); 86 | } 87 | 88 | default void expectInception(Exchange exchange) { 89 | addExpectation(ExternalService.INCEPTION, exchange); 90 | } 91 | 92 | private void addExpectation(ExternalService externalService, Exchange exchange) { 93 | Expectation expectation; 94 | if (exchange instanceof StreamHttpExchange) { 95 | expectation = new StreamExpectation(externalService, (StreamHttpExchange) exchange); 96 | } else if (exchange instanceof NdJsonStreamHttpExchange) { 97 | expectation = new NdJsonStreamExpectation(externalService, 98 | (NdJsonStreamHttpExchange) exchange); 99 | } else { 100 | expectation = new BasicExpectation(externalService, (BasicHttpExchange) exchange); 101 | } 102 | externalServiceServerMap.get(externalService) 103 | .addExpectation(expectation); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/ee/carlrobert/llm/client/anthropic/ClaudeClient.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client.anthropic; 2 | 3 | import static ee.carlrobert.llm.client.DeserializationUtil.OBJECT_MAPPER; 4 | 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import ee.carlrobert.llm.PropertiesLoader; 7 | import ee.carlrobert.llm.client.DeserializationUtil; 8 | import ee.carlrobert.llm.client.anthropic.completion.ClaudeCompletionEventSourceListener; 9 | import ee.carlrobert.llm.client.anthropic.completion.ClaudeCompletionException; 10 | import ee.carlrobert.llm.client.anthropic.completion.ClaudeCompletionRequest; 11 | import ee.carlrobert.llm.client.anthropic.completion.ClaudeCompletionResponse; 12 | import ee.carlrobert.llm.completion.CompletionEventListener; 13 | import ee.carlrobert.llm.completion.CompletionEventSourceListener; 14 | import java.io.IOException; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | import okhttp3.Headers; 18 | import okhttp3.MediaType; 19 | import okhttp3.OkHttpClient; 20 | import okhttp3.Request; 21 | import okhttp3.RequestBody; 22 | import okhttp3.sse.EventSource; 23 | import okhttp3.sse.EventSources; 24 | 25 | public class ClaudeClient { 26 | 27 | private static final MediaType APPLICATION_JSON = MediaType.parse("application/json"); 28 | 29 | private final OkHttpClient httpClient; 30 | private final String apiKey; 31 | private final String apiVersion; 32 | private final String host; 33 | 34 | public ClaudeClient(Builder builder, OkHttpClient.Builder httpClientBuilder) { 35 | this.apiKey = builder.apiKey; 36 | this.apiVersion = builder.apiVersion; 37 | this.host = builder.host; 38 | this.httpClient = httpClientBuilder.build(); 39 | } 40 | 41 | public EventSource getCompletionAsync( 42 | ClaudeCompletionRequest request, 43 | CompletionEventListener eventListener) { 44 | return EventSources.createFactory(httpClient).newEventSource( 45 | buildCompletionRequest(request), 46 | getCompletionEventSourceListener(eventListener)); 47 | } 48 | 49 | public ClaudeCompletionResponse getCompletion(ClaudeCompletionRequest request) { 50 | try (var response = httpClient.newCall(buildCompletionRequest(request)).execute()) { 51 | return DeserializationUtil.mapResponse(response, ClaudeCompletionResponse.class); 52 | } catch (IOException e) { 53 | throw new ClaudeCompletionException("Failed to communicate with Claude API", e); 54 | } 55 | } 56 | 57 | protected Request buildCompletionRequest(ClaudeCompletionRequest request) { 58 | var headers = new HashMap<>(getRequiredHeaders()); 59 | if (request.isStream()) { 60 | headers.put("Accept", "text/event-stream"); 61 | } 62 | try { 63 | return new Request.Builder() 64 | .url(host + "/v1/messages") 65 | .headers(Headers.of(headers)) 66 | .post(RequestBody.create(OBJECT_MAPPER.writeValueAsString(request), APPLICATION_JSON)) 67 | .build(); 68 | } catch (JsonProcessingException e) { 69 | throw new ClaudeCompletionException("Failed to serialize request to JSON", e); 70 | } 71 | } 72 | 73 | private Map getRequiredHeaders() { 74 | return new HashMap<>(Map.of("x-api-key", apiKey, "anthropic-version", apiVersion)); 75 | } 76 | 77 | private CompletionEventSourceListener getCompletionEventSourceListener( 78 | CompletionEventListener eventListener) { 79 | return new ClaudeCompletionEventSourceListener(eventListener); 80 | } 81 | 82 | public static class Builder { 83 | 84 | private final String apiKey; 85 | private final String apiVersion; 86 | private String host = PropertiesLoader.getValue("anthropic.baseUrl"); 87 | 88 | public Builder(String apiKey, String apiVersion) { 89 | this.apiKey = apiKey; 90 | this.apiVersion = apiVersion; 91 | } 92 | 93 | public Builder setHost(String host) { 94 | this.host = host; 95 | return this; 96 | } 97 | 98 | public ClaudeClient build(OkHttpClient.Builder builder) { 99 | return new ClaudeClient(this, builder); 100 | } 101 | 102 | public ClaudeClient build() { 103 | return build(new OkHttpClient.Builder()); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/test/java/ee/carlrobert/llm/client/YouClientTest.java: -------------------------------------------------------------------------------- 1 | package ee.carlrobert.llm.client; 2 | 3 | import static ee.carlrobert.llm.client.util.JSONUtil.jsonMapResponse; 4 | import static java.util.concurrent.TimeUnit.SECONDS; 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | import static org.awaitility.Awaitility.await; 7 | 8 | import ee.carlrobert.llm.client.http.exchange.StreamHttpExchange; 9 | import ee.carlrobert.llm.client.you.UTMParameters; 10 | import ee.carlrobert.llm.client.you.YouClient; 11 | import ee.carlrobert.llm.client.you.completion.YouCompletionCustomModel; 12 | import ee.carlrobert.llm.client.you.completion.YouCompletionMode; 13 | import ee.carlrobert.llm.client.you.completion.YouCompletionRequest; 14 | import ee.carlrobert.llm.client.you.completion.YouCompletionRequestMessage; 15 | import ee.carlrobert.llm.completion.CompletionEventListener; 16 | import java.util.List; 17 | import java.util.UUID; 18 | import okhttp3.sse.EventSource; 19 | import org.junit.jupiter.api.Test; 20 | 21 | public class YouClientTest extends BaseTest { 22 | 23 | @Test 24 | void shouldStreamYouChatCompletion() { 25 | var utmParameters = new UTMParameters(); 26 | utmParameters.setId("TEST_ID"); 27 | utmParameters.setSource("TEST_SOURCE"); 28 | utmParameters.setMedium("TEST_MEDIUM"); 29 | utmParameters.setCampaign("TEST_CAMPAIGN"); 30 | utmParameters.setContent("TEST_CONTENT"); 31 | utmParameters.setTerm("TEST_TERM"); 32 | var userId = UUID.randomUUID(); 33 | var chatId = UUID.randomUUID(); 34 | var queryTraceId = UUID.randomUUID(); 35 | expectYou((StreamHttpExchange) request -> { 36 | assertThat(request.getUri().getPath()).isEqualTo("/api/streamingSearch"); 37 | assertThat(request.getMethod()).isEqualTo("GET"); 38 | assertThat(request.getUri().getQuery()).isEqualTo( 39 | "q=TEST_PROMPT&" 40 | + "page=1&" 41 | + "cfr=CodeGPT&" 42 | + "count=10&" 43 | + "safeSearch=WebPages,Translations,TimeZone,Computation,RelatedSearches&" 44 | + "domain=youchat&" 45 | + "selectedChatMode=custom&" 46 | + "chat=[{\"question\":\"Ping\",\"answer\":\"Pong\"}]&" 47 | + "selectedAIModel=gemini_pro&" 48 | + "chatId=" + chatId + "&" 49 | + "queryTraceId=" + queryTraceId + "&" 50 | + "utm_id=TEST_ID&" 51 | + "utm_source=TEST_SOURCE&" 52 | + "utm_medium=TEST_MEDIUM&" 53 | + "utm_campaign=TEST_CAMPAIGN&" 54 | + "utm_content=TEST_CONTENT&" 55 | + "utm_term=TEST_TERM"); 56 | assertThat(request.getHeaders()) 57 | .flatExtracting("Accept", "Connection", "User-agent", "Cookie") 58 | .containsExactly( 59 | "text/event-stream", 60 | "Keep-Alive", 61 | "youide CodeGPT", 62 | "uuid_guest=" + userId + "; " 63 | + "safesearch_guest=Moderate; " 64 | + "youpro_subscription=true; " 65 | + "you_subscription=free; " 66 | + "stytch_session=TEST_SESSION_ID; " 67 | + "ydc_stytch_session=TEST_SESSION_ID; " 68 | + "stytch_session_jwt=TEST_ACCESS_TOKEN; " 69 | + "ydc_stytch_session_jwt=TEST_ACCESS_TOKEN; " 70 | + "eg4=true; " 71 | + "__cf_bm=aN2b3pQMH8XADeMB7bg9s1bJ_bfXBcCHophfOGRg6g0-1693601599-0-AWIt5Mr4Y3xQI" 72 | + "4mIJ1lSf4+vijWKDobrty8OopDeBxY+NABe0MRFidF3dCUoWjRt8SVMvBZPI3zkOgcRs7Mz3yazd7f" 73 | + "7c58HwW5Xg9jdBjNg;"); 74 | return List.of( 75 | jsonMapResponse("youChatToken", "Hel"), 76 | jsonMapResponse("youChatToken", "lo"), 77 | jsonMapResponse("youChatToken", "!")); 78 | }); 79 | var resultMessageBuilder = new StringBuilder(); 80 | 81 | new YouClient.Builder("TEST_SESSION_ID", "TEST_ACCESS_TOKEN") 82 | .setUTMParameters(utmParameters) 83 | .build() 84 | .getChatCompletionAsync( 85 | new YouCompletionRequest.Builder("TEST_PROMPT") 86 | .setChatHistory(List.of(new YouCompletionRequestMessage("Ping", "Pong"))) 87 | .setChatId(chatId) 88 | .setUserId(userId) 89 | .setUseGPT4Model(true) 90 | .setQueryTraceId(queryTraceId) 91 | .setChatMode(YouCompletionMode.CUSTOM) 92 | .setCustomModel(YouCompletionCustomModel.GEMINI_PRO) 93 | .build(), 94 | new CompletionEventListener() { 95 | @Override 96 | public void onMessage(String message, EventSource eventSource) { 97 | resultMessageBuilder.append(message); 98 | } 99 | }); 100 | 101 | await().atMost(5, SECONDS).until(() -> "Hello!".contentEquals(resultMessageBuilder)); 102 | } 103 | } 104 | --------------------------------------------------------------------------------