Skip to content

Commit

Permalink
Merge pull request #76 from devoxx/issue-74
Browse files Browse the repository at this point in the history
Issue 74
  • Loading branch information
stephanj authored May 21, 2024
2 parents c0970a8 + dd8c906 commit b589e61
Show file tree
Hide file tree
Showing 22 changed files with 309 additions and 20 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

group = "com.devoxx.genie"
version = "0.1.10"
version = "0.1.11"

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.devoxx.genie.chatmodel.ollama.OllamaChatModelFactory;
import com.devoxx.genie.chatmodel.openai.OpenAIChatModelFactory;
import com.devoxx.genie.chatmodel.gemini.GeminiChatModelFactory;
import com.devoxx.genie.chatmodel.jan.JanChatModelFactory;
import org.jetbrains.annotations.NotNull;

import java.util.Map;
Expand All @@ -26,8 +27,9 @@ public class ChatModelFactoryProvider {
ModelProvider.Mistral, MistralChatModelFactory::new,
ModelProvider.Groq, GroqChatModelFactory::new,
ModelProvider.DeepInfra, DeepInfraChatModelFactory::new,
ModelProvider.Gemini, GeminiChatModelFactory::new
);
ModelProvider.Gemini, GeminiChatModelFactory::new,
ModelProvider.Jan, JanChatModelFactory::new
);

/**
* Get the factory by provider.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.devoxx.genie.chatmodel.gemini.GeminiChatModelFactory;
import com.devoxx.genie.chatmodel.gpt4all.GPT4AllChatModelFactory;
import com.devoxx.genie.chatmodel.groq.GroqChatModelFactory;
import com.devoxx.genie.chatmodel.jan.JanChatModelFactory;
import com.devoxx.genie.chatmodel.lmstudio.LMStudioChatModelFactory;
import com.devoxx.genie.chatmodel.mistral.MistralChatModelFactory;
import com.devoxx.genie.chatmodel.ollama.OllamaChatModelFactory;
Expand Down Expand Up @@ -38,6 +39,7 @@ public ChatModelProvider() {
factories.put(ModelProvider.Anthropic, new AnthropicChatModelFactory());
factories.put(ModelProvider.Groq, new GroqChatModelFactory());
factories.put(ModelProvider.Gemini, new GeminiChatModelFactory());
factories.put(ModelProvider.Jan, new JanChatModelFactory());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ private LLMProviderConstant() {
protected static final String[] llmProviders = {
GPT4All.getName(),
LMStudio.getName(),
Ollama.getName()
Ollama.getName(),
Jan.getName()
};

public static @NotNull List<String> getLLMProviders() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.devoxx.genie.chatmodel.jan;

import com.devoxx.genie.chatmodel.ChatModelFactory;
import com.devoxx.genie.model.ChatModel;
import com.devoxx.genie.model.jan.Data;
import com.devoxx.genie.service.JanService;
import com.devoxx.genie.ui.SettingsState;
import com.devoxx.genie.ui.util.NotificationUtil;
import com.intellij.openapi.project.ProjectManager;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.localai.LocalAiChatModel;
import okhttp3.OkHttpClient;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

public class JanChatModelFactory implements ChatModelFactory {

// Moved client instance here for the sake of better performance
private final OkHttpClient client = new OkHttpClient();

@Override
public ChatLanguageModel createChatModel(@NotNull ChatModel chatModel) {
return LocalAiChatModel.builder()
.baseUrl(SettingsState.getInstance().getJanModelUrl())
.modelName(chatModel.getModelName())
.maxRetries(chatModel.getMaxRetries())
.temperature(chatModel.getTemperature())
.maxTokens(chatModel.getMaxTokens())
.timeout(Duration.ofSeconds(chatModel.getTimeout()))
.topP(chatModel.getTopP())
.build();
}

/**
* Get the model names from the Jan service.
* @return List of model names
*/
@Override
public List<String> getModelNames() {
List<String> modelNames = new ArrayList<>();
try {
List<Data> models = new JanService(client).getModels();
for (Data model : models) {
modelNames.add(model.getId());
}
} catch (IOException e) {
NotificationUtil.sendNotification(ProjectManager.getInstance().getDefaultProject(),
"Jan is not running or model not installed.");
}
return modelNames;
}
}
1 change: 1 addition & 0 deletions src/main/java/com/devoxx/genie/model/Constant.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ private Constant() {
public static final String OLLAMA_MODEL_URL = "http://localhost:11434/";
public static final String LMSTUDIO_MODEL_URL = "http://localhost:1234/v1/";
public static final String GPT4ALL_MODEL_URL = "http://localhost:4891/v1/";
public static final String JAN_MODEL_URL = "http://localhost:1337/v1/";

// The LLM Settings
public static final Double TEMPERATURE = 0.7d;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public enum ModelProvider {
Mistral("Mistral"),
Groq("Groq"),
DeepInfra("DeepInfra"),
Gemini("Gemini");
Gemini("Gemini"),
Jan("Jan");

private final String name;

Expand Down
39 changes: 39 additions & 0 deletions src/main/java/com/devoxx/genie/model/jan/Data.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.devoxx.genie.model.jan;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Data {
@JsonProperty("id")
private String id;

@JsonProperty("object")
private String object;

@JsonProperty("name")
private String name;

@JsonProperty("version")
private String version;

@JsonProperty("description")
private String description;

@JsonProperty("format")
private String format;

@JsonProperty("settings")
private Settings settings;

@JsonProperty("parameters")
private Parameters parameters;

@JsonProperty("metadata")
private Metadata metadata;

@JsonProperty("engine")
private String engine;
}
23 changes: 23 additions & 0 deletions src/main/java/com/devoxx/genie/model/jan/Metadata.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.devoxx.genie.model.jan;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
public class Metadata {
@JsonProperty("author")
private String author;

@JsonProperty("tags")
private List<String> tags;

@JsonProperty("size")
private long size;

@JsonProperty("cover")
private String cover;
}
32 changes: 32 additions & 0 deletions src/main/java/com/devoxx/genie/model/jan/Parameters.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.devoxx.genie.model.jan;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
public class Parameters {
@JsonProperty("temperature")
private double temperature;

@JsonProperty("top_p")
private double topP;

@JsonProperty("stream")
private boolean stream;

@JsonProperty("max_tokens")
private int maxTokens;

@JsonProperty("stop")
private List<String> stop;

@JsonProperty("frequency_penalty")
private double frequencyPenalty;

@JsonProperty("presence_penalty")
private double presencePenalty;
}
19 changes: 19 additions & 0 deletions src/main/java/com/devoxx/genie/model/jan/ResponseDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.devoxx.genie.model.jan;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Setter
@Getter
public class ResponseDTO {

@JsonProperty("object")
private String object;

@JsonProperty("data")
private List<Data> data;

}
21 changes: 21 additions & 0 deletions src/main/java/com/devoxx/genie/model/jan/Settings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.devoxx.genie.model.jan;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Settings {
@JsonProperty("ctx_len")
private int ctxLen;

@JsonProperty("prompt_template")
private String promptTemplate;

@JsonProperty("llama_model_path")
private String llamaModelPath;

@JsonProperty("ngl")
private int ngl;
}
52 changes: 52 additions & 0 deletions src/main/java/com/devoxx/genie/service/JanService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.devoxx.genie.service;

import com.devoxx.genie.model.jan.Data;
import com.devoxx.genie.model.jan.ResponseDTO;
import com.devoxx.genie.ui.SettingsState;
import com.google.gson.Gson;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.List;

public class JanService {
private final OkHttpClient client;

public JanService(OkHttpClient client) {
this.client = client;
}

public List<Data> getModels() throws IOException {
String baseUrl = ensureEndsWithSlash(SettingsState.getInstance().getJanModelUrl());

Request request = new Request.Builder()
.url(baseUrl + "models")
.build();

try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new UnsuccessfulRequestException("Unexpected code " + response);
}

assert response.body() != null;

ResponseDTO responseDTO = new Gson().fromJson(response.body().string(), ResponseDTO.class);
return responseDTO != null && responseDTO.getData() != null ? responseDTO.getData() : List.of();
}
}

@Contract(pure = true)
private String ensureEndsWithSlash(@NotNull String url) {
return url.endsWith("/") ? url : url + "/";
}

public static class UnsuccessfulRequestException extends IOException {
public UnsuccessfulRequestException(String message) {
super(message);
}
}
}
5 changes: 4 additions & 1 deletion src/main/java/com/devoxx/genie/service/OllamaService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

Expand Down Expand Up @@ -36,7 +38,8 @@ public OllamaModelEntryDTO[] getModels() throws IOException {
}
}

private String ensureEndsWithSlash(String url) {
@Contract(pure = true)
private String ensureEndsWithSlash(@NotNull String url) {
return url.endsWith("/") ? url : url + "/";
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class DevoxxGenieSettingsManager implements Configurable {
private JTextField ollamaUrlField;
private JTextField lmstudioUrlField;
private JTextField gpt4allUrlField;
private JTextField janUrlField;

private JPasswordField openAiKeyField;
private JPasswordField mistralKeyField;
Expand Down Expand Up @@ -80,6 +81,7 @@ public JComponent createComponent() {
ollamaUrlField = addFieldWithLinkButton(settingsPanel, gbc, "Ollama URL:", settings.getOllamaModelUrl(), "https://ollama.com/");
lmstudioUrlField = addFieldWithLinkButton(settingsPanel, gbc, "LMStudio URL:", settings.getLmstudioModelUrl(), "https://lmstudio.ai/");
gpt4allUrlField = addFieldWithLinkButton(settingsPanel, gbc, "GPT4All URL:", settings.getGpt4allModelUrl(), "https://gpt4all.io/");
janUrlField = addFieldWithLinkButton(settingsPanel, gbc, "Jan URL:", settings.getJanModelUrl(), "https://jan.ai/download");

setTitle("Cloud based Large Language Models", settingsPanel, gbc);

Expand Down Expand Up @@ -268,6 +270,7 @@ public boolean isModified() {
boolean isModified = isFieldModified(ollamaUrlField, settings.getOllamaModelUrl());
isModified |= isFieldModified(lmstudioUrlField, settings.getLmstudioModelUrl());
isModified |= isFieldModified(gpt4allUrlField, settings.getGpt4allModelUrl());
isModified |= isFieldModified(janUrlField, settings.getJanModelUrl());
isModified |= isFieldModified(temperatureField, Objects.requireNonNull(doubleConverter.toString(settings.getTemperature())));
isModified |= isFieldModified(topPField, Objects.requireNonNull(doubleConverter.toString(settings.getTopP())));
isModified |= isFieldModified(timeoutField, settings.getTimeout());
Expand All @@ -293,6 +296,7 @@ public void apply() {
updateSettingIfModified(ollamaUrlField, settings.getOllamaModelUrl(), settings::setOllamaModelUrl);
updateSettingIfModified(lmstudioUrlField, settings.getLmstudioModelUrl(), settings::setLmstudioModelUrl);
updateSettingIfModified(gpt4allUrlField, settings.getGpt4allModelUrl(), settings::setGpt4allModelUrl);
updateSettingIfModified(janUrlField, settings.getJanModelUrl(), settings::setJanModelUrl);
updateSettingIfModified(temperatureField, doubleConverter.toString(settings.getTemperature()), value -> settings.setTemperature(doubleConverter.fromString(value)));
updateSettingIfModified(topPField, doubleConverter.toString(settings.getTopP()), value -> settings.setTopP(doubleConverter.fromString(value)));
updateSettingIfModified(timeoutField, settings.getTimeout(), value -> settings.setTimeout(safeCastToInteger(value)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public class DevoxxGenieToolWindowContent implements SettingsChangeListener, Con
private boolean isInitializationComplete = false;
private final EditorFileButtonManager editorFileButtonManager;

private Logger LOG = Logger.getInstance(DevoxxGenieToolWindowContent.class);
private final Logger LOG = Logger.getInstance(DevoxxGenieToolWindowContent.class);

/**
* The Devoxx Genie Tool Window Content constructor.
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/devoxx/genie/ui/SettingsState.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
@State(name = "com.devoxx.genie.ui.SettingsState", storages = @Storage("DevoxxGenieSettingsPlugin.xml"))
public final class SettingsState implements PersistentStateComponent<SettingsState> {

// LLM URL fields
// Local LLM URL fields
private String ollamaModelUrl = Constant.OLLAMA_MODEL_URL;
private String lmstudioModelUrl = Constant.LMSTUDIO_MODEL_URL;
private String gpt4allModelUrl = Constant.GPT4ALL_MODEL_URL;
private String janModelUrl = Constant.JAN_MODEL_URL;

// LLM API Keys
private String openAIKey = "";
Expand Down
Loading

0 comments on commit b589e61

Please sign in to comment.