diff --git a/build.gradle.kts b/build.gradle.kts index 7a02783b..c913421e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,8 +20,7 @@ dependencies { implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.2") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2") implementation("com.fifesoft:rsyntaxtextarea:3.3.2") - implementation("com.squareup.okhttp3:okhttp:4.10.0") - implementation("com.squareup.okhttp3:okhttp-sse:4.10.0") + implementation("ee.carlrobert:openai-client:1.0.1") } java { diff --git a/src/main/java/ee/carlrobert/codegpt/PluginStartupActivity.java b/src/main/java/ee/carlrobert/codegpt/PluginStartupActivity.java new file mode 100644 index 00000000..c7ef0296 --- /dev/null +++ b/src/main/java/ee/carlrobert/codegpt/PluginStartupActivity.java @@ -0,0 +1,23 @@ +package ee.carlrobert.codegpt; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.startup.StartupActivity; +import ee.carlrobert.codegpt.account.AccountDetailsState; +import ee.carlrobert.codegpt.action.ActionsUtil; +import ee.carlrobert.codegpt.client.ClientFactory; +import ee.carlrobert.codegpt.settings.configuration.ConfigurationState; +import org.jetbrains.annotations.NotNull; + +public class PluginStartupActivity implements StartupActivity { + + @Override + public void runActivity(@NotNull Project project) { + ActionsUtil.refreshActions(ConfigurationState.getInstance().tableData); + var accountDetails = AccountDetailsState.getInstance(); + if ("User".equals(accountDetails.accountName) || accountDetails.accountName == null) { + ClientFactory.getBillingClient() + .getSubscriptionAsync(subscription -> + accountDetails.accountName = subscription.getAccountName()); + } + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/ide/account/AccountDetailsState.java b/src/main/java/ee/carlrobert/codegpt/account/AccountDetailsState.java similarity index 89% rename from src/main/java/ee/carlrobert/codegpt/ide/account/AccountDetailsState.java rename to src/main/java/ee/carlrobert/codegpt/account/AccountDetailsState.java index 10028ea5..2708c0f5 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/account/AccountDetailsState.java +++ b/src/main/java/ee/carlrobert/codegpt/account/AccountDetailsState.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.account; +package ee.carlrobert.codegpt.account; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; @@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @State( - name = "ee.carlrobert.codegpt.ide.account.AccountDetailsState", + name = "ee.carlrobert.codegpt.account.AccountDetailsState", storages = @Storage("CodeGPTAccountDetails.xml") ) public class AccountDetailsState implements PersistentStateComponent { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/action/ActionsUtil.java b/src/main/java/ee/carlrobert/codegpt/action/ActionsUtil.java similarity index 97% rename from src/main/java/ee/carlrobert/codegpt/ide/action/ActionsUtil.java rename to src/main/java/ee/carlrobert/codegpt/action/ActionsUtil.java index 0ad6abff..b8033b9e 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/action/ActionsUtil.java +++ b/src/main/java/ee/carlrobert/codegpt/action/ActionsUtil.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.action; +package ee.carlrobert.codegpt.action; import static java.lang.String.format; import static java.util.stream.Collectors.toList; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/action/AskAction.java b/src/main/java/ee/carlrobert/codegpt/action/AskAction.java similarity index 78% rename from src/main/java/ee/carlrobert/codegpt/ide/action/AskAction.java rename to src/main/java/ee/carlrobert/codegpt/action/AskAction.java index a983e9b8..210a32b8 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/action/AskAction.java +++ b/src/main/java/ee/carlrobert/codegpt/action/AskAction.java @@ -1,11 +1,11 @@ -package ee.carlrobert.codegpt.ide.action; +package ee.carlrobert.codegpt.action; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; -import ee.carlrobert.codegpt.ide.toolwindow.ContentManagerService; -import ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService; +import ee.carlrobert.codegpt.conversations.ConversationsState; +import ee.carlrobert.codegpt.toolwindow.ContentManagerService; +import ee.carlrobert.codegpt.toolwindow.ToolWindowService; import org.jetbrains.annotations.NotNull; public class AskAction extends AnAction { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/action/BaseAction.java b/src/main/java/ee/carlrobert/codegpt/action/BaseAction.java similarity index 89% rename from src/main/java/ee/carlrobert/codegpt/ide/action/BaseAction.java rename to src/main/java/ee/carlrobert/codegpt/action/BaseAction.java index ed16ffb9..90be410f 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/action/BaseAction.java +++ b/src/main/java/ee/carlrobert/codegpt/action/BaseAction.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.action; +package ee.carlrobert.codegpt.action; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -6,9 +6,9 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NlsActions; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; -import ee.carlrobert.codegpt.ide.toolwindow.ContentManagerService; -import ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService; +import ee.carlrobert.codegpt.conversations.ConversationsState; +import ee.carlrobert.codegpt.toolwindow.ContentManagerService; +import ee.carlrobert.codegpt.toolwindow.ToolWindowService; import javax.swing.Icon; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/action/CustomPromptAction.java b/src/main/java/ee/carlrobert/codegpt/action/CustomPromptAction.java similarity index 96% rename from src/main/java/ee/carlrobert/codegpt/ide/action/CustomPromptAction.java rename to src/main/java/ee/carlrobert/codegpt/action/CustomPromptAction.java index 9f1f869c..dad3bd20 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/action/CustomPromptAction.java +++ b/src/main/java/ee/carlrobert/codegpt/action/CustomPromptAction.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.action; +package ee.carlrobert.codegpt.action; import com.intellij.icons.AllIcons; import com.intellij.openapi.editor.Editor; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/action/CustomPromptDialog.java b/src/main/java/ee/carlrobert/codegpt/action/CustomPromptDialog.java similarity index 92% rename from src/main/java/ee/carlrobert/codegpt/ide/action/CustomPromptDialog.java rename to src/main/java/ee/carlrobert/codegpt/action/CustomPromptDialog.java index 102b9b40..cfda24e7 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/action/CustomPromptDialog.java +++ b/src/main/java/ee/carlrobert/codegpt/action/CustomPromptDialog.java @@ -1,13 +1,13 @@ -package ee.carlrobert.codegpt.ide.action; +package ee.carlrobert.codegpt.action; -import static ee.carlrobert.codegpt.ide.util.SwingUtils.addShiftEnterInputMap; +import static ee.carlrobert.codegpt.util.SwingUtils.addShiftEnterInputMap; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.ui.components.JBScrollPane; import com.intellij.util.ui.FormBuilder; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UI; -import ee.carlrobert.codegpt.ide.toolwindow.components.SyntaxTextArea; +import ee.carlrobert.codegpt.toolwindow.components.SyntaxTextArea; import javax.annotation.Nullable; import javax.swing.JComponent; import javax.swing.JTextArea; diff --git a/src/main/java/ee/carlrobert/codegpt/client/ApiRequestDetails.java b/src/main/java/ee/carlrobert/codegpt/client/ApiRequestDetails.java deleted file mode 100644 index 3ab9731c..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/ApiRequestDetails.java +++ /dev/null @@ -1,26 +0,0 @@ -package ee.carlrobert.codegpt.client; - -public class ApiRequestDetails { - - private final String url; - private final Object body; - private final String token; - - public ApiRequestDetails(String url, Object body, String token) { - this.url = url; - this.body = body; - this.token = token; - } - - public String getUrl() { - return url; - } - - public Object getBody() { - return body; - } - - public String getToken() { - return token; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/BaseApiResponse.java b/src/main/java/ee/carlrobert/codegpt/client/BaseApiResponse.java deleted file mode 100644 index f2f0c7b3..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/BaseApiResponse.java +++ /dev/null @@ -1,4 +0,0 @@ -package ee.carlrobert.codegpt.client; - -public interface BaseApiResponse { -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/BaseModel.java b/src/main/java/ee/carlrobert/codegpt/client/BaseModel.java deleted file mode 100644 index 5720bc71..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/BaseModel.java +++ /dev/null @@ -1,29 +0,0 @@ -package ee.carlrobert.codegpt.client; - -public enum BaseModel { - - ADA("text-ada-001", "Ada - Fastest"), - BABBAGE("text-babbage-001", "Babbage - Powerful"), - CURIE("text-curie-001", "Curie - Fast and efficient"), - DAVINCI("text-davinci-003", "Davinci - Most powerful (Default)"), - CHATGPT("gpt-3.5-turbo", "ChatGPT(3.5) - Most capable model (Default)"), - CHATGPT_SNAPSHOT("gpt-3.5-turbo-0301", "ChatGPT(3.5) - Snapshot of gpt-3.5-turbo from March 1st 2023"), - CHATGPT_4("gpt-4", "ChatGPT(4.0) - Most recent model (Requires access which is behind the waitlist approval process)"), - UNOFFICIAL_CHATGPT("text-davinci-002-render-sha", "Unofficial ChatGPT"); - - private final String code; - private final String description; - - BaseModel(String code, String description) { - this.code = code; - this.description = description; - } - - public String getCode() { - return code; - } - - public String getDescription() { - return description; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/Client.java b/src/main/java/ee/carlrobert/codegpt/client/Client.java deleted file mode 100644 index 20fb0e73..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/Client.java +++ /dev/null @@ -1,166 +0,0 @@ -package ee.carlrobert.codegpt.client; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; -import ee.carlrobert.codegpt.ide.settings.SettingsState; -import ee.carlrobert.codegpt.ide.settings.advanced.AdvancedSettingsState; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import okhttp3.Credentials; -import okhttp3.Headers; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.sse.EventSource; -import okhttp3.sse.EventSourceListener; -import okhttp3.sse.EventSources; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class Client { - - private static final Logger LOG = LoggerFactory.getLogger(Client.class); - - private final ObjectMapper objectMapper = new ObjectMapper(); - private final ClientCode clientCode; - private EventSource eventSource; - protected Conversation conversation; - protected String prompt; - protected OkHttpClient client; - - protected Client(ClientCode clientCode) { - this.clientCode = clientCode; - } - - protected abstract ApiRequestDetails getRequestDetails(String prompt); - - protected abstract EventSourceListener getEventSourceListener( - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure); - - public void getCompletionsAsync( - String prompt, - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure) { - var conversationsState = ConversationsState.getInstance(); - this.conversation = ConversationsState.getCurrentConversation(); - if (conversation == null) { - this.conversation = conversationsState.startConversation(); - } - this.prompt = prompt; - this.client = buildClient(); - this.eventSource = EventSources.createFactory(client) - .newEventSource( - buildHttpRequest(prompt), - getEventSourceListener(onMessageReceived, onComplete, onFailure)); - } - - public CreditUsage getCreditGrants() { - try { - var response = buildClient().newCall(new Request.Builder() - .url("https://api.openai.com/dashboard/billing/credit_grants") - .headers(Headers.of(Map.of( - "Content-Type", "application/json", - "Authorization", "Bearer " + SettingsState.getInstance().apiKey - ))) - .get() - .build()) - .execute(); - - if (response.body() == null) { - return null; - } - - return objectMapper.readValue(response.body().string(), CreditUsage.class); - } catch (IOException ex) { - LOG.error("Unable to retrieve credit info", ex); - return null; - } - } - - public void getCreditUsageAsync(Consumer responseConsumer) { - buildClient() - .newCall(buildRequest("https://api.openai.com/dashboard/billing/credit_grants")) - .enqueue(new CreditUsageCallback(responseConsumer)); - } - - public void getSubscriptionAsync(Consumer responseConsumer) { - buildClient() - .newCall(buildRequest("https://api.openai.com/dashboard/billing/subscription")) - .enqueue(new SubscriptionCallback(responseConsumer)); - } - - public OkHttpClient buildClient() { - OkHttpClient.Builder builder = new OkHttpClient.Builder() - .connectTimeout(60, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS); - - var settings = AdvancedSettingsState.getInstance(); - var proxyHost = settings.proxyHost; - var proxyPort = settings.proxyPort; - if (!proxyHost.isEmpty() && proxyPort != 0) { - builder.proxy(new Proxy(settings.proxyType, new InetSocketAddress(proxyHost, proxyPort))); - - var username = settings.proxyUsername; - var password = settings.proxyPassword; - if (settings.isProxyAuthSelected) { - builder.proxyAuthenticator((route, response) -> - response.request() - .newBuilder() - .header("Proxy-Authorization", Credentials.basic(username, password)) - .build()); - } - } - - return builder.build(); - } - - public void cancelRequest() { - eventSource.cancel(); - } - - public Request buildHttpRequest(String prompt) { - var requestDetails = getRequestDetails(prompt); - try { - return new Request.Builder() - .url(requestDetails.getUrl()) - .headers(Headers.of(Map.of( - "Accept", "text/event-stream", - "Content-Type", "application/json", - "Authorization", "Bearer " + requestDetails.getToken() - ))) - .post(RequestBody.create( - objectMapper - .writerWithDefaultPrettyPrinter() - .writeValueAsString(requestDetails.getBody()), - MediaType.parse("application/json"))) - .build(); - } catch (JsonProcessingException e) { - throw new RuntimeException("Unable to serialize request payload", e); - } - } - - public ClientCode getCode() { - return clientCode; - } - - private Request buildRequest(String url) { - return new Request.Builder() - .url(url) - .headers(Headers.of(Map.of( - "Content-Type", "application/json", - "Authorization", "Bearer " + SettingsState.getInstance().apiKey - ))) - .get() - .build(); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/ClientCode.java b/src/main/java/ee/carlrobert/codegpt/client/ClientCode.java deleted file mode 100644 index bd5e82a6..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/ClientCode.java +++ /dev/null @@ -1,8 +0,0 @@ -package ee.carlrobert.codegpt.client; - -public enum ClientCode { - - CHAT_COMPLETIONS, - TEXT_COMPLETIONS, - UNOFFICIAL_CHATGPT -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/ClientFactory.java b/src/main/java/ee/carlrobert/codegpt/client/ClientFactory.java index e05e019f..9733bcdc 100644 --- a/src/main/java/ee/carlrobert/codegpt/client/ClientFactory.java +++ b/src/main/java/ee/carlrobert/codegpt/client/ClientFactory.java @@ -1,19 +1,47 @@ package ee.carlrobert.codegpt.client; -import ee.carlrobert.codegpt.client.unofficial.UnofficialChatGPTClient; -import ee.carlrobert.codegpt.client.official.chat.ChatCompletionClient; -import ee.carlrobert.codegpt.client.official.text.TextCompletionClient; -import ee.carlrobert.codegpt.ide.settings.SettingsState; +import ee.carlrobert.codegpt.settings.SettingsState; +import ee.carlrobert.codegpt.settings.advanced.AdvancedSettingsState; +import ee.carlrobert.openai.client.OpenAIClient; +import ee.carlrobert.openai.client.ProxyAuthenticator; +import ee.carlrobert.openai.client.billing.BillingClient; +import ee.carlrobert.openai.client.completion.chat.ChatCompletionClient; +import ee.carlrobert.openai.client.completion.text.TextCompletionClient; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.util.concurrent.TimeUnit; public class ClientFactory { - public Client getClient() { - if (SettingsState.getInstance().isGPTOptionSelected) { - if (SettingsState.getInstance().isChatCompletionOptionSelected) { - return ChatCompletionClient.getInstance(); + public static BillingClient getBillingClient() { + return getClientBuilder().buildBillingClient(); + } + + public static ChatCompletionClient getChatCompletionClient() { + return getClientBuilder().buildChatCompletionClient(); + } + + public static TextCompletionClient getTextCompletionClient() { + return getClientBuilder().buildTextCompletionClient(); + } + + private static OpenAIClient.Builder getClientBuilder() { + var builder = new OpenAIClient.Builder(SettingsState.getInstance().apiKey) // TODO: ENV var? + .setConnectTimeout(60L, TimeUnit.SECONDS) + .setReadTimeout(30L, TimeUnit.SECONDS); + + var settings = AdvancedSettingsState.getInstance(); + var proxyHost = settings.proxyHost; + var proxyPort = settings.proxyPort; + if (!proxyHost.isEmpty() && proxyPort != 0) { + builder.setProxy(new Proxy(settings.proxyType, new InetSocketAddress(proxyHost, proxyPort))); + if (settings.isProxyAuthSelected) { + builder.setProxyAuthenticator(new ProxyAuthenticator(settings.proxyUsername, settings.proxyPassword)); } - return TextCompletionClient.getInstance(); } - return UnofficialChatGPTClient.getInstance(); + + return builder; } } + + diff --git a/src/main/java/ee/carlrobert/codegpt/client/ClientRequestFactory.java b/src/main/java/ee/carlrobert/codegpt/client/ClientRequestFactory.java new file mode 100644 index 00000000..da29cd0a --- /dev/null +++ b/src/main/java/ee/carlrobert/codegpt/client/ClientRequestFactory.java @@ -0,0 +1,75 @@ +package ee.carlrobert.codegpt.client; + +import ee.carlrobert.codegpt.conversations.Conversation; +import ee.carlrobert.codegpt.settings.SettingsState; +import ee.carlrobert.openai.client.completion.chat.request.ChatCompletionMessage; +import ee.carlrobert.openai.client.completion.chat.request.ChatCompletionRequest; +import ee.carlrobert.openai.client.completion.text.TextCompletionModel; +import ee.carlrobert.openai.client.completion.text.request.TextCompletionRequest; +import java.util.ArrayList; +import java.util.List; + +public class ClientRequestFactory { + + private final String prompt; + private final Conversation conversation; + + public ClientRequestFactory(String prompt, Conversation conversation) { + this.prompt = prompt; + this.conversation = conversation; + } + + public ChatCompletionRequest buildChatCompletionRequest(SettingsState settings) { + return new ChatCompletionRequest.Builder(buildMessages(prompt, conversation)) + .setModel(settings.chatCompletionBaseModel.getCode()) + .build(); + } + + public TextCompletionRequest buildTextCompletionRequest(SettingsState settings) { + return new TextCompletionRequest.Builder(buildPrompt(conversation, prompt)) + .setStop(List.of(" Human:", " AI:")) + .setModel(settings.textCompletionBaseModel.getCode()) + .build(); + } + + private List buildMessages(String prompt, Conversation conversation) { + var messages = new ArrayList(); + messages.add(new ChatCompletionMessage( + "system", + "You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible.")); + conversation.getMessages().forEach(message -> { + messages.add(new ChatCompletionMessage("user", message.getPrompt())); + messages.add(new ChatCompletionMessage("assistant", message.getResponse())); + }); + messages.add(new ChatCompletionMessage("user", prompt)); + return messages; + } + + private StringBuilder getBasePrompt() { + var isDavinciModel = SettingsState.getInstance().textCompletionBaseModel == TextCompletionModel.DAVINCI; + if (isDavinciModel) { + return new StringBuilder( + "You are ChatGPT, a large language model trained by OpenAI.\n" + + "Answer in a markdown language, code blocks should contain language whenever possible.\n"); + } + return new StringBuilder( + "The following is a conversation with an AI assistant. The assistant is helpful, creative, clever, and very friendly.\n\n"); + } + + private String buildPrompt(Conversation conversation, String prompt) { + var basePrompt = getBasePrompt(); + conversation.getMessages().forEach(message -> + basePrompt.append("Human: ") + .append(message.getPrompt()) + .append("\n") + .append("AI: ") + .append(message.getResponse()) + .append("\n")); + basePrompt.append("Human: ") + .append(prompt) + .append("\n") + .append("AI: ") + .append("\n"); + return basePrompt.toString(); + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/client/CreditUsage.java b/src/main/java/ee/carlrobert/codegpt/client/CreditUsage.java deleted file mode 100644 index a9369993..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/CreditUsage.java +++ /dev/null @@ -1,28 +0,0 @@ -package ee.carlrobert.codegpt.client; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class CreditUsage { - - private final Double totalGranted; - private final Double totalUsed; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public CreditUsage( - @JsonProperty("total_granted") Double totalGranted, - @JsonProperty("total_used") Double totalUsed) { - this.totalGranted = totalGranted; - this.totalUsed = totalUsed; - } - - public Double getTotalGranted() { - return totalGranted; - } - - public Double getTotalUsed() { - return totalUsed; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/CreditUsageCallback.java b/src/main/java/ee/carlrobert/codegpt/client/CreditUsageCallback.java deleted file mode 100644 index 8384f097..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/CreditUsageCallback.java +++ /dev/null @@ -1,37 +0,0 @@ -package ee.carlrobert.codegpt.client; - -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.util.function.Consumer; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Response; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CreditUsageCallback implements Callback { - - private static final Logger LOG = LoggerFactory.getLogger(CreditUsageCallback.class); - - private final Consumer creditUsageConsumer; - - CreditUsageCallback(Consumer creditUsageConsumer) { - this.creditUsageConsumer = creditUsageConsumer; - } - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - LOG.warn("Unable to retrieve credit info", e); - } - - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) { - if (response.body() != null) { - try { - creditUsageConsumer.accept(new ObjectMapper().readValue(response.body().string(), CreditUsage.class)); - } catch (IOException ex) { - LOG.warn("Unable to deserialize credit info response", ex); - } - } - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/EventListener.java b/src/main/java/ee/carlrobert/codegpt/client/EventListener.java new file mode 100644 index 00000000..349830e3 --- /dev/null +++ b/src/main/java/ee/carlrobert/codegpt/client/EventListener.java @@ -0,0 +1,44 @@ +package ee.carlrobert.codegpt.client; + +import ee.carlrobert.codegpt.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.message.Message; +import ee.carlrobert.openai.client.completion.CompletionEventListener; +import java.util.function.Consumer; + +public class EventListener implements CompletionEventListener { + + private final Message message; + private final Consumer onAppend; + private final Runnable onStopGenerating; + + public EventListener(Message message, Consumer onAppend, Runnable onStopGenerating) { + this.onStopGenerating = onStopGenerating; + this.onAppend = onAppend; + this.message = message; + } + + @Override + public void onComplete(StringBuilder messageBuilder) { + saveConversation(messageBuilder.toString()); + onStopGenerating.run(); + } + + @Override + public void onFailure(String errorMessage) { + saveConversation(errorMessage); + onAppend.accept("\n" + errorMessage); + onStopGenerating.run(); + } + + private void saveConversation(String response) { + var conversationsState = ConversationsState.getInstance(); + var currentConversation = ConversationsState.getCurrentConversation(); + final var conversation = currentConversation == null ? + conversationsState.startConversation() : + currentConversation; + + message.setResponse(response); + conversation.addMessage(message); + conversationsState.saveConversation(conversation); + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/client/Subscription.java b/src/main/java/ee/carlrobert/codegpt/client/Subscription.java deleted file mode 100644 index c98b9075..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/Subscription.java +++ /dev/null @@ -1,20 +0,0 @@ -package ee.carlrobert.codegpt.client; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class Subscription { - - private final String accountName; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Subscription(@JsonProperty("account_name") String accountName) { - this.accountName = accountName; - } - - public String getAccountName() { - return accountName; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/SubscriptionCallback.java b/src/main/java/ee/carlrobert/codegpt/client/SubscriptionCallback.java deleted file mode 100644 index 61fdbdfc..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/SubscriptionCallback.java +++ /dev/null @@ -1,38 +0,0 @@ -package ee.carlrobert.codegpt.client; - -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.util.function.Consumer; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Response; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class SubscriptionCallback implements Callback { - - private static final Logger LOG = LoggerFactory.getLogger(SubscriptionCallback.class); - - private final Consumer subscriptionConsumer; - - SubscriptionCallback(Consumer subscriptionConsumer) { - this.subscriptionConsumer = subscriptionConsumer; - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - LOG.warn("Unable to retrieve subscription info", e); - } - - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) { - if (response.body() != null) { - try { - subscriptionConsumer.accept(new ObjectMapper().readValue(response.body().string(), Subscription.class)); - } catch (IOException ex) { - LOG.warn("Unable to deserialize subscription response", ex); - } - } - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/ApiResponseError.java b/src/main/java/ee/carlrobert/codegpt/client/official/ApiResponseError.java deleted file mode 100644 index 06e3e9fd..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/ApiResponseError.java +++ /dev/null @@ -1,40 +0,0 @@ -package ee.carlrobert.codegpt.client.official; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponseError { - - private final ErrorDetails error; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponseError(@JsonProperty("error") ErrorDetails error) { - this.error = error; - } - - public ErrorDetails getError() { - return error; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - static class ErrorDetails { - private final String message; - private final String type; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ErrorDetails(@JsonProperty("message") String message, @JsonProperty("type") String type) { - this.message = message; - this.type = type; - } - - public String getMessage() { - return message; - } - - public String getType() { - return type; - } - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/CompletionClientEventListener.java b/src/main/java/ee/carlrobert/codegpt/client/official/CompletionClientEventListener.java deleted file mode 100644 index 3e6107ce..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/CompletionClientEventListener.java +++ /dev/null @@ -1,104 +0,0 @@ -package ee.carlrobert.codegpt.client.official; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.net.SocketTimeoutException; -import java.util.function.Consumer; -import javax.annotation.Nullable; -import okhttp3.Call; -import okhttp3.OkHttpClient; -import okhttp3.Response; -import okhttp3.sse.EventSource; -import okhttp3.sse.EventSourceListener; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class CompletionClientEventListener extends EventSourceListener { - - private static final Logger LOG = LoggerFactory.getLogger(CompletionClientEventListener.class); - - private static final String DEFAULT_ERROR_MSG = "Something went wrong. Please try again later."; - - private final OkHttpClient client; - private final Consumer onMessageReceived; - private final Consumer onComplete; - private final Consumer onFailure; - private final StringBuilder messageBuilder = new StringBuilder(); - - public CompletionClientEventListener( - OkHttpClient client, - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure) { - this.client = client; - this.onMessageReceived = onMessageReceived; - this.onComplete = onComplete; - this.onFailure = onFailure; - } - - protected abstract String getMessage(String data) throws JsonProcessingException; - - public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) { - } - - public void onClosed(@NotNull EventSource eventSource) { - } - - public void onEvent( - @NotNull EventSource eventSource, - @Nullable String id, - @Nullable String type, - @NotNull String data) { - try { - if ("[DONE]".equals(data)) { - onComplete.accept(messageBuilder.toString()); - return; - } - - var message = getMessage(data); - if (message != null) { - messageBuilder.append(message); - onMessageReceived.accept(message); - } - } catch (JsonProcessingException e) { - throw new RuntimeException("Unable to deserialize payload.", e); - } - } - - public void onFailure( - @NotNull EventSource eventSource, - @Nullable Throwable ex, - @Nullable Response response) { - if (isRequestCancelled()) { - onComplete.accept(messageBuilder.toString()); - return; - } - - if (ex instanceof SocketTimeoutException) { - onFailure.accept("Request timed out. This may be due to the server being overloaded."); - return; - } - - try { - if (response == null) { - onFailure.accept(DEFAULT_ERROR_MSG); - return; - } - - var body = response.body(); - if (body != null) { - var error = new ObjectMapper().readValue(body.string(), ApiResponseError.class); - onFailure.accept(error.getError().getMessage()); - } - } catch (IOException e) { - LOG.error("Something went wrong.", ex); - onFailure.accept(DEFAULT_ERROR_MSG); - } - } - - private boolean isRequestCancelled() { - return client.dispatcher().runningCalls().stream().anyMatch(Call::isCanceled); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/chat/ChatCompletionClient.java b/src/main/java/ee/carlrobert/codegpt/client/official/chat/ChatCompletionClient.java deleted file mode 100644 index 00720a15..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/chat/ChatCompletionClient.java +++ /dev/null @@ -1,64 +0,0 @@ -package ee.carlrobert.codegpt.client.official.chat; - -import ee.carlrobert.codegpt.client.ApiRequestDetails; -import ee.carlrobert.codegpt.client.Client; -import ee.carlrobert.codegpt.client.ClientCode; -import ee.carlrobert.codegpt.client.official.chat.request.ApiRequest; -import ee.carlrobert.codegpt.client.official.chat.request.ApiRequestMessage; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.message.Message; -import ee.carlrobert.codegpt.ide.settings.SettingsState; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.function.Consumer; -import okhttp3.sse.EventSourceListener; - -public class ChatCompletionClient extends Client { - - private static ChatCompletionClient instance; - - private ChatCompletionClient() { - super(ClientCode.CHAT_COMPLETIONS); - } - - public static ChatCompletionClient getInstance() { - if (instance == null) { - instance = new ChatCompletionClient(); - } - return instance; - } - - protected ApiRequestDetails getRequestDetails(String prompt) { - var messages = new ArrayList(); - messages.add(new ApiRequestMessage( - "system", - "You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible.")); - conversation.getMessages().forEach(message -> { - messages.add(new ApiRequestMessage("user", message.getPrompt())); - messages.add(new ApiRequestMessage("assistant", message.getResponse())); - }); - messages.add(new ApiRequestMessage("user", prompt)); - - return new ApiRequestDetails( - "https://api.openai.com/v1/chat/completions", - new ApiRequest( - SettingsState.getInstance().chatCompletionBaseModel.getCode(), - true, - messages - ), - SettingsState.getInstance().apiKey); - } - - protected EventSourceListener getEventSourceListener( - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure) { - return new ChatCompletionClientEventListener(client, onMessageReceived, finalMessage -> { - var message = new Message(prompt); - message.setResponse(finalMessage); - conversation.setUpdatedOn(LocalDateTime.now()); - conversation.addMessage(message); - onComplete.accept(conversation); - }, onFailure); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/chat/ChatCompletionClientEventListener.java b/src/main/java/ee/carlrobert/codegpt/client/official/chat/ChatCompletionClientEventListener.java deleted file mode 100644 index 3dd98d4a..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/chat/ChatCompletionClientEventListener.java +++ /dev/null @@ -1,28 +0,0 @@ -package ee.carlrobert.codegpt.client.official.chat; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import ee.carlrobert.codegpt.client.official.CompletionClientEventListener; -import ee.carlrobert.codegpt.client.official.chat.response.ApiResponse; -import java.util.function.Consumer; -import okhttp3.OkHttpClient; - -public class ChatCompletionClientEventListener extends CompletionClientEventListener { - - public ChatCompletionClientEventListener( - OkHttpClient client, - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure) { - super(client, onMessageReceived, onComplete, onFailure); - } - - protected String getMessage(String data) throws JsonProcessingException { - return new ObjectMapper() - .readValue(data, ApiResponse.class) - .getChoices() - .get(0) - .getDelta() - .getContent(); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/chat/request/ApiRequest.java b/src/main/java/ee/carlrobert/codegpt/client/official/chat/request/ApiRequest.java deleted file mode 100644 index c1fb9b31..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/chat/request/ApiRequest.java +++ /dev/null @@ -1,28 +0,0 @@ -package ee.carlrobert.codegpt.client.official.chat.request; - -import java.util.List; - -public class ApiRequest { - - private final String model; - private final boolean stream; - private final List messages; - - public ApiRequest(String model, boolean stream, List messages) { - this.model = model; - this.stream = stream; - this.messages = messages; - } - - public String getModel() { - return model; - } - - public boolean isStream() { - return stream; - } - - public List getMessages() { - return messages; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/chat/request/ApiRequestMessage.java b/src/main/java/ee/carlrobert/codegpt/client/official/chat/request/ApiRequestMessage.java deleted file mode 100644 index 9921daca..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/chat/request/ApiRequestMessage.java +++ /dev/null @@ -1,20 +0,0 @@ -package ee.carlrobert.codegpt.client.official.chat.request; - -public class ApiRequestMessage { - - private final String role; - private final String content; - - public ApiRequestMessage(String role, String content) { - this.role = role; - this.content = content; - } - - public String getRole() { - return role; - } - - public String getContent() { - return content; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponse.java b/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponse.java deleted file mode 100644 index 31c2683a..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package ee.carlrobert.codegpt.client.official.chat.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import ee.carlrobert.codegpt.client.BaseApiResponse; -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponse implements BaseApiResponse { - - private final String id; - private final List choices; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponse( - @JsonProperty("id") String id, - @JsonProperty("choices") List choices) { - this.id = id; - this.choices = choices; - } - - public String getId() { - return id; - } - - public List getChoices() { - return choices; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponseChoice.java b/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponseChoice.java deleted file mode 100644 index e4dec230..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponseChoice.java +++ /dev/null @@ -1,20 +0,0 @@ -package ee.carlrobert.codegpt.client.official.chat.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponseChoice { - - private final ApiResponseChoiceDelta delta; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponseChoice(@JsonProperty("delta") ApiResponseChoiceDelta delta) { - this.delta = delta; - } - - public ApiResponseChoiceDelta getDelta() { - return delta; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponseChoiceDelta.java b/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponseChoiceDelta.java deleted file mode 100644 index 4e417a64..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/chat/response/ApiResponseChoiceDelta.java +++ /dev/null @@ -1,28 +0,0 @@ -package ee.carlrobert.codegpt.client.official.chat.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponseChoiceDelta { - - private final String role; - private final String content; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponseChoiceDelta( - @JsonProperty("role") String role, - @JsonProperty("content") String content) { - this.role = role; - this.content = content; - } - - public String getRole() { - return role; - } - - public String getContent() { - return content; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/text/TextCompletionClient.java b/src/main/java/ee/carlrobert/codegpt/client/official/text/TextCompletionClient.java deleted file mode 100644 index 5f98d8d0..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/text/TextCompletionClient.java +++ /dev/null @@ -1,89 +0,0 @@ -package ee.carlrobert.codegpt.client.official.text; - -import static java.lang.String.format; - -import ee.carlrobert.codegpt.client.ApiRequestDetails; -import ee.carlrobert.codegpt.client.BaseModel; -import ee.carlrobert.codegpt.client.Client; -import ee.carlrobert.codegpt.client.ClientCode; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.message.Message; -import ee.carlrobert.codegpt.ide.settings.SettingsState; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import okhttp3.sse.EventSourceListener; - -public class TextCompletionClient extends Client { - - private static TextCompletionClient instance; - - private TextCompletionClient() { - super(ClientCode.TEXT_COMPLETIONS); - } - - public static TextCompletionClient getInstance() { - if (instance == null) { - instance = new TextCompletionClient(); - } - return instance; - } - - protected ApiRequestDetails getRequestDetails(String prompt) { - return new ApiRequestDetails( - format("https://api.openai.com/v1/engines/%s/completions", - SettingsState.getInstance().textCompletionBaseModel.getCode()), - Map.of( - "stop", List.of(" Human:", " AI:"), - "prompt", buildPrompt(prompt), - "max_tokens", 1000, - "temperature", 0.9, - "best_of", 1, - "frequency_penalty", 0, - "presence_penalty", 0.6, - "top_p", 1, - "stream", true - ), - SettingsState.getInstance().apiKey); - } - - protected EventSourceListener getEventSourceListener( - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure) { - return new TextCompletionClientEventListener(client, onMessageReceived, (finalMessage) -> { - conversation.setUpdatedOn(LocalDateTime.now()); - conversation.addMessage(new Message(prompt, finalMessage)); - onComplete.accept(conversation); - }, onFailure); - } - - private StringBuilder getBasePrompt() { - var isDavinciModel = SettingsState.getInstance().textCompletionBaseModel == BaseModel.DAVINCI; - if (isDavinciModel) { - return new StringBuilder( - "You are ChatGPT, a large language model trained by OpenAI.\n" + - "Answer in a markdown language, code blocks should contain language whenever possible.\n"); - } - return new StringBuilder( - "The following is a conversation with an AI assistant. The assistant is helpful, creative, clever, and very friendly.\n\n"); - } - - private String buildPrompt(String prompt) { - var basePrompt = getBasePrompt(); - conversation.getMessages().forEach(message -> - basePrompt.append("Human: ") - .append(message.getPrompt()) - .append("\n") - .append("AI: ") - .append(message.getResponse()) - .append("\n")); - basePrompt.append("Human: ") - .append(prompt) - .append("\n") - .append("AI: ") - .append("\n"); - return basePrompt.toString(); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/text/TextCompletionClientEventListener.java b/src/main/java/ee/carlrobert/codegpt/client/official/text/TextCompletionClientEventListener.java deleted file mode 100644 index 5fb3f5f5..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/text/TextCompletionClientEventListener.java +++ /dev/null @@ -1,27 +0,0 @@ -package ee.carlrobert.codegpt.client.official.text; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import ee.carlrobert.codegpt.client.official.CompletionClientEventListener; -import ee.carlrobert.codegpt.client.official.text.response.ApiResponse; -import java.util.function.Consumer; -import okhttp3.OkHttpClient; - -public class TextCompletionClientEventListener extends CompletionClientEventListener { - - public TextCompletionClientEventListener( - OkHttpClient client, - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure) { - super(client, onMessageReceived, onComplete, onFailure); - } - - protected String getMessage(String data) throws JsonProcessingException { - return new ObjectMapper() - .readValue(data, ApiResponse.class) - .getChoices() - .get(0) - .getText(); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/text/response/ApiResponse.java b/src/main/java/ee/carlrobert/codegpt/client/official/text/response/ApiResponse.java deleted file mode 100644 index 5ca8baee..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/text/response/ApiResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -package ee.carlrobert.codegpt.client.official.text.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import ee.carlrobert.codegpt.client.BaseApiResponse; -import java.util.List; - -// TODO: BaseCompletionApiResponse / CompletionApiResponse -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponse implements BaseApiResponse { - - private final String id; - private final List choices; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponse( - @JsonProperty("id") String id, - @JsonProperty("choices") List choices) { - this.id = id; - this.choices = choices; - } - - public String getId() { - return id; - } - - public List getChoices() { - return choices; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/official/text/response/ApiResponseChoice.java b/src/main/java/ee/carlrobert/codegpt/client/official/text/response/ApiResponseChoice.java deleted file mode 100644 index 4eea6f89..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/official/text/response/ApiResponseChoice.java +++ /dev/null @@ -1,28 +0,0 @@ -package ee.carlrobert.codegpt.client.official.text.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponseChoice { - - private final String text; - private final String finishReason; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponseChoice( - @JsonProperty("text") String text, - @JsonProperty("finish_reason") String finishReason) { - this.text = text; - this.finishReason = finishReason; - } - - public String getText() { - return text; - } - - public String getFinishReason() { - return finishReason; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/unofficial/UnofficialChatGPTClient.java b/src/main/java/ee/carlrobert/codegpt/client/unofficial/UnofficialChatGPTClient.java deleted file mode 100644 index 5ee2363c..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/unofficial/UnofficialChatGPTClient.java +++ /dev/null @@ -1,76 +0,0 @@ -package ee.carlrobert.codegpt.client.unofficial; - -import ee.carlrobert.codegpt.client.ApiRequestDetails; -import ee.carlrobert.codegpt.client.Client; -import ee.carlrobert.codegpt.client.ClientCode; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.message.Message; -import ee.carlrobert.codegpt.ide.settings.SettingsState; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Consumer; -import okhttp3.sse.EventSourceListener; - -public class UnofficialChatGPTClient extends Client { - - private static UnofficialChatGPTClient instance; - - private UnofficialChatGPTClient() { - super(ClientCode.UNOFFICIAL_CHATGPT); - } - - public static UnofficialChatGPTClient getInstance() { - if (instance == null) { - instance = new UnofficialChatGPTClient(); - } - return instance; - } - - protected EventSourceListener getEventSourceListener( - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure) { - return new UnofficialClientEventListener(client, prompt, onMessageReceived, (response) -> { - var message = new Message(prompt); - message.setResponse(response.getFullMessage()); - - conversation.setUnofficialClientConversationId(response.getConversationId()); - conversation.setParentMessageId(response.getMessage().getId()); - conversation.setUpdatedOn(LocalDateTime.now()); - conversation.addMessage(message); - onComplete.accept(conversation); - }, onFailure); - } - - protected ApiRequestDetails getRequestDetails(String prompt) { - var settings = SettingsState.getInstance(); - var payload = new HashMap<>(Map.of( - "action", "next", - "messages", List.of(Map.of( - "id", UUID.randomUUID().toString(), - "role", "user", - "author", Map.of("role", "user"), - "content", Map.of( - "content_type", "text", - "parts", List.of(prompt) - ) - )), - "model", "text-davinci-002-render-sha" - )); - - var conversationId = conversation.getUnofficialClientConversationId(); - var parentMessageId = conversation.getParentMessageId(); - if (conversationId != null && !conversationId.isEmpty() && - parentMessageId != null && !parentMessageId.isEmpty()) { - payload.put("conversation_id", conversationId); - payload.put("parent_message_id", parentMessageId); - } else { - payload.put("parent_message_id", UUID.randomUUID().toString()); - } - - return new ApiRequestDetails(settings.reverseProxyUrl, payload, settings.accessToken); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/unofficial/UnofficialClientEventListener.java b/src/main/java/ee/carlrobert/codegpt/client/unofficial/UnofficialClientEventListener.java deleted file mode 100644 index 1c228dc3..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/unofficial/UnofficialClientEventListener.java +++ /dev/null @@ -1,148 +0,0 @@ -package ee.carlrobert.codegpt.client.unofficial; - -import com.fasterxml.jackson.core.JacksonException; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import ee.carlrobert.codegpt.client.unofficial.response.ApiResponse; -import java.io.IOException; -import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; -import javax.annotation.Nullable; -import okhttp3.Call; -import okhttp3.OkHttpClient; -import okhttp3.Response; -import okhttp3.sse.EventSource; -import okhttp3.sse.EventSourceListener; -import org.jetbrains.annotations.NotNull; - -public class UnofficialClientEventListener extends EventSourceListener { - - private final ObjectMapper objectMapper = new ObjectMapper(); - private final String prompt; - private final Consumer onMessageReceived; - private final Consumer<@NotNull ApiResponse> onComplete; - private final Consumer onFailure; - private ApiResponse lastReceivedResponse; - private boolean eventReceived = false; - private final OkHttpClient client; - - public UnofficialClientEventListener( - OkHttpClient client, - String prompt, - Consumer onMessageReceived, - Consumer onComplete, - Consumer onFailure) { - this.client = client; - this.prompt = prompt; - this.onMessageReceived = onMessageReceived; - this.onComplete = onComplete; - this.onFailure = onFailure; - } - - public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) { - } - - public void onClosed(@NotNull EventSource eventSource) { - if (!eventReceived) { - var clientInstance = UnofficialChatGPTClient.getInstance(); - try { - var response = clientInstance.buildClient() - .newCall(clientInstance.buildHttpRequest(prompt)) - .execute(); - tryExtractingErrorResponse(response); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - public void onEvent( - @NotNull EventSource eventSource, - @Nullable String id, - @Nullable String type, - @NotNull String data) { - eventReceived = true; - - if ("[DONE]".equals(data)) { - onComplete.accept(lastReceivedResponse); - return; - } - - if (!"ping".equals(type) && isValidJson(data)) { - try { - var response = objectMapper.readValue(data, ApiResponse.class); - var author = response.getMessage().getAuthor(); - if (author != null && "assistant".equals(author.getRole())) { - var message = response.getFullMessage(); - if (lastReceivedResponse != null) { - message = message.replace(lastReceivedResponse.getFullMessage(), ""); - } - lastReceivedResponse = response; - onMessageReceived.accept(message); - } - } catch (JsonProcessingException e) { - throw new RuntimeException("Unable to deserialize the payload", e); - } - } - } - - public void onFailure( - @NotNull EventSource eventSource, - @Nullable Throwable ex, - @Nullable Response response) { - if (isRequestNotCancelled() && response != null) { - try { - tryExtractingErrorResponse(response); - } catch (Exception e) { - onFailure.accept("Something went wrong. Please try again later."); - } - } else { - onComplete.accept(lastReceivedResponse); - } - } - - private boolean isRequestNotCancelled() { - return client.dispatcher().runningCalls().stream().noneMatch(Call::isCanceled); - } - - private void tryExtractingErrorResponse(Response response) { - try (response) { - var responseBody = response.body(); - if (responseBody != null) { - tryExtractingErrorMessage(responseBody.string()).ifPresent(onFailure); - responseBody.close(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private Optional tryExtractingErrorMessage(String jsonPayload) { - try { - var error = objectMapper.readValue(jsonPayload, Map.class); - var detail = error.get("detail"); - if (detail instanceof String) { - return Optional.of((String) detail); - } else if (detail instanceof Map) { - return Optional.of((String) ((Map) detail).get("message")); - } else { - return Optional.empty(); - } - } catch (JsonProcessingException e) { - return Optional.empty(); - } - } - - private boolean isValidJson(String json) { - ObjectMapper mapper = new ObjectMapper() - .enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS); - try { - mapper.readTree(json); - } catch (JacksonException e) { - return false; - } - return true; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponse.java b/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponse.java deleted file mode 100644 index e8c15c6c..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package ee.carlrobert.codegpt.client.unofficial.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import ee.carlrobert.codegpt.client.BaseApiResponse; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponse implements BaseApiResponse { - - private final ApiResponseMessage message; - private final String conversationId; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponse( - @JsonProperty("message") ApiResponseMessage message, - @JsonProperty("conversation_id") String conversationId) { - this.message = message; - this.conversationId = conversationId; - } - - public ApiResponseMessage getMessage() { - return message; - } - - public String getConversationId() { - return conversationId; - } - - public String getFullMessage() { - return String.join("", message.getContent().getParts()); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessage.java b/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessage.java deleted file mode 100644 index f404dd11..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessage.java +++ /dev/null @@ -1,35 +0,0 @@ -package ee.carlrobert.codegpt.client.unofficial.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponseMessage { - - private final String id; - private final ApiResponseMessageAuthor author; - private final ApiResponseMessageContent content; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponseMessage( - @JsonProperty("id") String id, - @JsonProperty("author") ApiResponseMessageAuthor author, - @JsonProperty("content") ApiResponseMessageContent content) { - this.id = id; - this.author = author; - this.content = content; - } - - public String getId() { - return id; - } - - public ApiResponseMessageAuthor getAuthor() { - return author; - } - - public ApiResponseMessageContent getContent() { - return content; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessageAuthor.java b/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessageAuthor.java deleted file mode 100644 index c58f5ec6..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessageAuthor.java +++ /dev/null @@ -1,20 +0,0 @@ -package ee.carlrobert.codegpt.client.unofficial.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponseMessageAuthor { - - private final String role; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponseMessageAuthor(@JsonProperty("role") String role) { - this.role = role; - } - - public String getRole() { - return role; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessageContent.java b/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessageContent.java deleted file mode 100644 index 0e21e9d4..00000000 --- a/src/main/java/ee/carlrobert/codegpt/client/unofficial/response/ApiResponseMessageContent.java +++ /dev/null @@ -1,26 +0,0 @@ -package ee.carlrobert.codegpt.client.unofficial.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiResponseMessageContent { - - private final String contentType; - private final List parts; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public ApiResponseMessageContent(String contentType, List parts) { - this.contentType = contentType; - this.parts = parts; - } - - public String getContentType() { - return contentType; - } - - public List getParts() { - return parts; - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/ide/conversations/Conversation.java b/src/main/java/ee/carlrobert/codegpt/conversations/Conversation.java similarity index 58% rename from src/main/java/ee/carlrobert/codegpt/ide/conversations/Conversation.java rename to src/main/java/ee/carlrobert/codegpt/conversations/Conversation.java index e6f53d24..f85410f9 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/conversations/Conversation.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/Conversation.java @@ -1,8 +1,8 @@ -package ee.carlrobert.codegpt.ide.conversations; +package ee.carlrobert.codegpt.conversations; -import ee.carlrobert.codegpt.client.BaseModel; -import ee.carlrobert.codegpt.client.ClientCode; -import ee.carlrobert.codegpt.ide.conversations.message.Message; +import ee.carlrobert.codegpt.conversations.message.Message; +import ee.carlrobert.openai.client.ClientCode; +import ee.carlrobert.openai.client.completion.CompletionModel; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -11,11 +11,9 @@ import java.util.UUID; public class Conversation { private UUID id; - private String parentMessageId; - private String unofficialClientConversationId; private List messages = new ArrayList<>(); private ClientCode clientCode; - private BaseModel model; + private CompletionModel model; private LocalDateTime createdOn; private LocalDateTime updatedOn; @@ -27,22 +25,6 @@ public class Conversation { this.id = id; } - public String getParentMessageId() { - return parentMessageId; - } - - public void setParentMessageId(String parentMessageId) { - this.parentMessageId = parentMessageId; - } - - public String getUnofficialClientConversationId() { - return unofficialClientConversationId; - } - - public void setUnofficialClientConversationId(String unofficialClientConversationId) { - this.unofficialClientConversationId = unofficialClientConversationId; - } - public List getMessages() { return messages; } @@ -63,11 +45,11 @@ public class Conversation { messages.add(message); } - public BaseModel getModel() { + public CompletionModel getModel() { return model; } - public void setModel(BaseModel model) { + public void setModel(CompletionModel model) { this.model = model; } diff --git a/src/main/java/ee/carlrobert/codegpt/ide/conversations/ConversationsContainer.java b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsContainer.java similarity index 82% rename from src/main/java/ee/carlrobert/codegpt/ide/conversations/ConversationsContainer.java rename to src/main/java/ee/carlrobert/codegpt/conversations/ConversationsContainer.java index 7ada9f43..8157c2ec 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/conversations/ConversationsContainer.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsContainer.java @@ -1,6 +1,6 @@ -package ee.carlrobert.codegpt.ide.conversations; +package ee.carlrobert.codegpt.conversations; -import ee.carlrobert.codegpt.client.ClientCode; +import ee.carlrobert.openai.client.ClientCode; import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/conversations/ConversationsState.java b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java similarity index 84% rename from src/main/java/ee/carlrobert/codegpt/ide/conversations/ConversationsState.java rename to src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java index ed32b762..4a34cda5 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/conversations/ConversationsState.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.conversations; +package ee.carlrobert.codegpt.conversations; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; @@ -6,12 +6,10 @@ import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.util.xmlb.XmlSerializerUtil; import com.intellij.util.xmlb.annotations.OptionTag; -import ee.carlrobert.codegpt.client.BaseModel; -import ee.carlrobert.codegpt.client.ClientCode; -import ee.carlrobert.codegpt.client.ClientFactory; -import ee.carlrobert.codegpt.ide.conversations.converter.ConversationConverter; -import ee.carlrobert.codegpt.ide.conversations.converter.ConversationsConverter; -import ee.carlrobert.codegpt.ide.settings.SettingsState; +import ee.carlrobert.codegpt.conversations.converter.ConversationConverter; +import ee.carlrobert.codegpt.conversations.converter.ConversationsConverter; +import ee.carlrobert.codegpt.settings.SettingsState; +import ee.carlrobert.openai.client.ClientCode; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Comparator; @@ -23,7 +21,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @State( - name = "ee.carlrobert.codegpt.ide.conversations.ConversationsState", + name = "ee.carlrobert.codegpt.conversations.ConversationsState", storages = @Storage("ChatGPTConversations.xml") ) public class ConversationsState implements PersistentStateComponent { @@ -72,14 +70,9 @@ public class ConversationsState implements PersistentStateComponent { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/conversations/converter/ConversationsConverter.java b/src/main/java/ee/carlrobert/codegpt/conversations/converter/ConversationsConverter.java similarity index 56% rename from src/main/java/ee/carlrobert/codegpt/ide/conversations/converter/ConversationsConverter.java rename to src/main/java/ee/carlrobert/codegpt/conversations/converter/ConversationsConverter.java index 2d739685..38ad2618 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/conversations/converter/ConversationsConverter.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/converter/ConversationsConverter.java @@ -1,6 +1,6 @@ -package ee.carlrobert.codegpt.ide.conversations.converter; +package ee.carlrobert.codegpt.conversations.converter; -import ee.carlrobert.codegpt.ide.conversations.ConversationsContainer; +import ee.carlrobert.codegpt.conversations.ConversationsContainer; public class ConversationsConverter extends BaseConverter { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/conversations/message/Message.java b/src/main/java/ee/carlrobert/codegpt/conversations/message/Message.java similarity index 91% rename from src/main/java/ee/carlrobert/codegpt/ide/conversations/message/Message.java rename to src/main/java/ee/carlrobert/codegpt/conversations/message/Message.java index 68bbdf67..bc6d42a7 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/conversations/message/Message.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/message/Message.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.conversations.message; +package ee.carlrobert.codegpt.conversations.message; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/PluginStartupActivity.java b/src/main/java/ee/carlrobert/codegpt/ide/PluginStartupActivity.java deleted file mode 100644 index be7b1439..00000000 --- a/src/main/java/ee/carlrobert/codegpt/ide/PluginStartupActivity.java +++ /dev/null @@ -1,23 +0,0 @@ -package ee.carlrobert.codegpt.ide; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupActivity; -import ee.carlrobert.codegpt.client.ClientFactory; -import ee.carlrobert.codegpt.ide.account.AccountDetailsState; -import ee.carlrobert.codegpt.ide.action.ActionsUtil; -import ee.carlrobert.codegpt.ide.settings.configuration.ConfigurationState; -import org.jetbrains.annotations.NotNull; - -public class PluginStartupActivity implements StartupActivity { - - @Override - public void runActivity(@NotNull Project project) { - ConfigurationState cfgState = ConfigurationState.getInstance(); - ActionsUtil.refreshActions(cfgState.tableData); - var accountDetails = AccountDetailsState.getInstance(); - if ("User".equals(accountDetails.accountName)) { - new ClientFactory().getClient() - .getSubscriptionAsync(subscription -> accountDetails.accountName = subscription.getAccountName()); - } - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsComponent.java b/src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsComponent.java deleted file mode 100644 index 2becc7de..00000000 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsComponent.java +++ /dev/null @@ -1,270 +0,0 @@ -package ee.carlrobert.codegpt.ide.settings; - -import com.intellij.openapi.ui.ComboBox; -import com.intellij.ui.TitledSeparator; -import com.intellij.ui.components.JBRadioButton; -import com.intellij.ui.components.JBTextField; -import com.intellij.util.ui.FormBuilder; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UI; -import ee.carlrobert.codegpt.client.BaseModel; -import ee.carlrobert.codegpt.ide.util.SwingUtils; -import java.awt.Desktop; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.List; -import javax.swing.ButtonGroup; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.event.HyperlinkEvent; -import org.jetbrains.annotations.NotNull; - -public class SettingsComponent { - - private final JPanel mainPanel; - private final JBTextField apiKeyField; - private final ComboBox chatCompletionBaseModelComboBox; - private final ComboBox textCompletionBaseModelComboBox; - private final ComboBox reverseProxyComboBox; - private final JBTextField accessTokenField; - private final JBRadioButton useGPTRadioButton; - private final JBRadioButton useChatCompletionRadioButton; - private final JBRadioButton useTextCompletionRadioButton; - private final JBRadioButton useChatGPTRadioButton; - - public SettingsComponent(SettingsState settings) { - apiKeyField = new JBTextField(settings.apiKey, 1); - chatCompletionBaseModelComboBox = new BaseModelComboBox( - new BaseModel[] { - BaseModel.CHATGPT, - BaseModel.CHATGPT_SNAPSHOT, - BaseModel.CHATGPT_4 - }, - settings.textCompletionBaseModel); - textCompletionBaseModelComboBox = new BaseModelComboBox( - new BaseModel[] { - BaseModel.DAVINCI, - BaseModel.CURIE, - BaseModel.BABBAGE, - BaseModel.ADA, - }, - settings.textCompletionBaseModel); - reverseProxyComboBox = new ComboBox<>(new String[] { - "https://bypass.duti.tech/api/conversation", - }, 400); - reverseProxyComboBox.setSelectedItem(settings.reverseProxyUrl); - accessTokenField = new JBTextField(settings.accessToken, 1); - useGPTRadioButton = new JBRadioButton("Use OpenAI's official API (recommended)", settings.isGPTOptionSelected); - useChatCompletionRadioButton = new JBRadioButton("Use chat completion", settings.isChatCompletionOptionSelected); - useTextCompletionRadioButton = new JBRadioButton("Use text completion", settings.isTextCompletionOptionSelected); - useChatGPTRadioButton = new JBRadioButton("Use ChatGPT's unofficial API (unstable)", settings.isChatGPTOptionSelected); - useChatGPTRadioButton.setEnabled(false); - mainPanel = FormBuilder.createFormBuilder() - .addComponent(new TitledSeparator("Integration Preference")) - .addVerticalGap(8) - .addComponent(createMainSelectionForm()) - .addVerticalGap(8) - .addComponentFillVertically(new JPanel(), 0) - .getPanel(); - - registerButtons(); - registerFields(settings.isChatGPTOptionSelected); - } - - public JPanel getPanel() { - return mainPanel; - } - - public JComponent getPreferredFocusedComponent() { - return apiKeyField; - } - - @NotNull - public String getApiKey() { - return apiKeyField.getText(); - } - - public void setApiKey(@NotNull String apiKey) { - apiKeyField.setText(apiKey); - } - - @NotNull - public String getAccessToken() { - return accessTokenField.getText(); - } - - public void setAccessToken(@NotNull String accessToken) { - accessTokenField.setText(accessToken); - } - - public boolean isGPTOptionSelected() { - return useGPTRadioButton.isSelected(); - } - - public void setUseGPTOptionSelected(boolean isSelected) { - useGPTRadioButton.setSelected(isSelected); - } - - public boolean isChatCompletionOptionSelected() { - return useChatCompletionRadioButton.isSelected(); - } - - public void setUseChatCompletionSelected(boolean isSelected) { - useChatCompletionRadioButton.setSelected(isSelected); - } - - public boolean isTextCompletionOptionSelected() { - return useTextCompletionRadioButton.isSelected(); - } - - public void setUseTextCompletionSelected(boolean isSelected) { - useTextCompletionRadioButton.setSelected(isSelected); - } - - public boolean isChatGPTOptionSelected() { - return useChatGPTRadioButton.isSelected(); - } - - public void setUseChatGPTOptionSelected(boolean isSelected) { - useChatGPTRadioButton.setSelected(isSelected); - } - - public String getReverseProxyUrl() { - return (String) reverseProxyComboBox.getSelectedItem(); - } - - public void setReverseProxyUrl(String reverseProxyUrl) { - reverseProxyComboBox.setSelectedItem(reverseProxyUrl); - } - - public BaseModel getTextCompletionBaseModel() { - return (BaseModel) textCompletionBaseModelComboBox.getSelectedItem(); - } - - public void setTextCompletionBaseModel(BaseModel baseModel) { - textCompletionBaseModelComboBox.setSelectedItem(baseModel); - } - - public BaseModel getChatCompletionBaseModel() { - return (BaseModel) chatCompletionBaseModelComboBox.getSelectedItem(); - } - - public void setChatCompletionBaseModel(BaseModel baseModel) { - chatCompletionBaseModelComboBox.setSelectedItem(baseModel); - } - - private JPanel createMainSelectionForm() { - var apiKeyFieldPanel = UI.PanelFactory.panel(apiKeyField) - .withLabel("API key:") - .withComment("You can find your Secret API key in your User settings.") - .withCommentHyperlinkListener(this::handleHyperlinkClicked) - .createPanel(); - apiKeyFieldPanel.setBorder(JBUI.Borders.emptyLeft(8)); - - var chatCompletionModelsPanel = SwingUtils.createPanel(chatCompletionBaseModelComboBox, "Model:", false); - chatCompletionModelsPanel.setBorder(JBUI.Borders.emptyLeft(24)); - - var textCompletionModelsPanel = SwingUtils.createPanel(textCompletionBaseModelComboBox, "Model:", false); - textCompletionModelsPanel.setBorder(JBUI.Borders.emptyLeft(24)); - - var gptRadioPanel = FormBuilder.createFormBuilder() - .addComponent(apiKeyFieldPanel) - .addComponent(UI.PanelFactory.panel(useChatCompletionRadioButton) - .withComment("OpenAI’s most advanced language model") - .createPanel()) - .addComponent(chatCompletionModelsPanel) - .addVerticalGap(8) - .addComponent(UI.PanelFactory.panel(useTextCompletionRadioButton) - .withComment("Best for high-quality texts") - .createPanel()) - .addComponent(textCompletionModelsPanel) - .getPanel(); - gptRadioPanel.setBorder(JBUI.Borders.emptyLeft(16)); - - - var panel = FormBuilder.createFormBuilder() - .addComponent(UI.PanelFactory.panel(useGPTRadioButton) - .withComment("Fast and robust, requires API key") - .createPanel()) - .addComponent(gptRadioPanel) - .addVerticalGap(8) - .addComponent(UI.PanelFactory.panel(useChatGPTRadioButton) - .withComment("Slow and free, more suitable for conversational tasks, rate-limited") - .createPanel()) - .addComponent(createSecondSelectionForm()) - .getPanel(); - panel.setBorder(JBUI.Borders.emptyLeft(16)); - return panel; - } - - private JPanel createSecondSelectionForm() { - var reverseProxyUrlPanel = SwingUtils.createPanel(reverseProxyComboBox, "Reverse proxy url:", false); - var accessTokenPanel = UI.PanelFactory.panel(accessTokenField) - .withLabel("Access token:") - .withComment( - "Access token can be obtained from https://chat.openai.com/api/auth/session.") - .withCommentHyperlinkListener(this::handleHyperlinkClicked) - .createPanel(); - - SwingUtils.setEqualLabelWidths(accessTokenPanel, reverseProxyUrlPanel); - - var panel = FormBuilder.createFormBuilder() - .addComponent(reverseProxyUrlPanel) - .addVerticalGap(8) - .addComponent(accessTokenPanel) - .getPanel(); - panel.setBorder(JBUI.Borders.emptyLeft(24)); - return panel; - } - - private void registerButtons() { - ButtonGroup myButtonGroup = new ButtonGroup(); - myButtonGroup.add(useGPTRadioButton); - myButtonGroup.add(useChatGPTRadioButton); - useGPTRadioButton.addActionListener(e -> registerFields(false)); - useChatGPTRadioButton.addActionListener(e -> registerFields(true)); - - ButtonGroup completionButtonGroup = new ButtonGroup(); - completionButtonGroup.add(useChatCompletionRadioButton); - completionButtonGroup.add(useTextCompletionRadioButton); - useChatCompletionRadioButton.addActionListener(e -> { - chatCompletionBaseModelComboBox.setEnabled(true); - textCompletionBaseModelComboBox.setEnabled(false); - }); - useTextCompletionRadioButton.addActionListener(e -> { - chatCompletionBaseModelComboBox.setEnabled(false); - textCompletionBaseModelComboBox.setEnabled(true); - }); - } - - private void registerFields(boolean isUseChatGPTOption) { - apiKeyField.setEnabled(!isUseChatGPTOption); - if (isUseChatGPTOption) { - List.of( - useChatCompletionRadioButton, - useTextCompletionRadioButton, - chatCompletionBaseModelComboBox, - textCompletionBaseModelComboBox - ).forEach(it -> it.setEnabled(false)); - } else { - useChatCompletionRadioButton.setEnabled(true); - useTextCompletionRadioButton.setEnabled(true); - chatCompletionBaseModelComboBox.setEnabled(useChatCompletionRadioButton.isSelected()); - textCompletionBaseModelComboBox.setEnabled(useTextCompletionRadioButton.isSelected()); - } - accessTokenField.setEnabled(isUseChatGPTOption); - reverseProxyComboBox.setEnabled(isUseChatGPTOption); - } - - private void handleHyperlinkClicked(HyperlinkEvent event) { - if (HyperlinkEvent.EventType.ACTIVATED.equals(event.getEventType())) { - if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { - try { - Desktop.getDesktop().browse(event.getURL().toURI()); - } catch (IOException | URISyntaxException e) { - throw new RuntimeException("Couldn't open the browser.", e); - } - } - } - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ToolWindowService.java b/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ToolWindowService.java deleted file mode 100644 index 6f2af801..00000000 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ToolWindowService.java +++ /dev/null @@ -1,73 +0,0 @@ -package ee.carlrobert.codegpt.ide.toolwindow; - -import com.intellij.ide.ui.LafManager; -import com.intellij.ide.ui.LafManagerListener; -import com.intellij.openapi.project.Project; -import ee.carlrobert.codegpt.client.ClientFactory; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; -import ee.carlrobert.codegpt.ide.conversations.message.Message; -import ee.carlrobert.codegpt.ide.toolwindow.chat.ChatGptToolWindow; -import ee.carlrobert.codegpt.ide.toolwindow.components.SyntaxTextArea; -import java.util.List; -import javax.swing.SwingWorker; -import org.jetbrains.annotations.NotNull; - -public class ToolWindowService implements LafManagerListener { - - private ChatGptToolWindow chatToolWindow; - - @Override - public void lookAndFeelChanged(@NotNull LafManager source) { - chatToolWindow.changeStyle(); - } - - public void setChatToolWindow(ChatGptToolWindow chatToolWindow) { - this.chatToolWindow = chatToolWindow; - } - - public ChatGptToolWindow getChatToolWindow() { - return chatToolWindow; - } - - public void startRequest(String prompt, SyntaxTextArea textArea, Project project) { - var client = new ClientFactory().getClient(); - chatToolWindow.displayGenerateButton(client::cancelRequest); - - var conversationMessage = new Message(prompt); - new SwingWorker() { - protected Void doInBackground() { - client.getCompletionsAsync( - prompt, - this::publish, - (completedConversation) -> { - ConversationsState.getInstance().saveConversation(completedConversation); - chatToolWindow.stopGenerating(prompt, textArea, project); - }, - (errorMessage) -> { - var currentConversation = ConversationsState.getCurrentConversation(); - if (currentConversation != null) { - conversationMessage.setResponse(errorMessage); - currentConversation.addMessage(conversationMessage); - ConversationsState.getInstance().saveConversation(currentConversation); - } - textArea.append(errorMessage); - chatToolWindow.stopGenerating(prompt, textArea, project); - }); - return null; - } - - protected void process(List chunks) { - for (String text : chunks) { - try { - textArea.append(text); - conversationMessage.setResponse(textArea.getText()); - chatToolWindow.scrollToBottom(); - } catch (Exception e) { - textArea.append("Something went wrong. Please try again later."); - throw new RuntimeException(e); - } - } - } - }.execute(); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/BaseModelComboBox.java b/src/main/java/ee/carlrobert/codegpt/settings/BaseModelComboBox.java similarity index 69% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/BaseModelComboBox.java rename to src/main/java/ee/carlrobert/codegpt/settings/BaseModelComboBox.java index 72563a3d..293d2d7f 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/BaseModelComboBox.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/BaseModelComboBox.java @@ -1,14 +1,14 @@ -package ee.carlrobert.codegpt.ide.settings; +package ee.carlrobert.codegpt.settings; import com.intellij.openapi.ui.ComboBox; -import ee.carlrobert.codegpt.client.BaseModel; +import ee.carlrobert.openai.client.completion.CompletionModel; import java.awt.Component; import javax.swing.JList; import javax.swing.plaf.basic.BasicComboBoxRenderer; -public class BaseModelComboBox extends ComboBox { +public class BaseModelComboBox extends ComboBox { - public BaseModelComboBox(BaseModel[] options, BaseModel selectedModel) { + public BaseModelComboBox(CompletionModel[] options, CompletionModel selectedModel) { super(options); setSelectedItem(selectedModel); setRenderer(getBasicComboBoxRenderer()); @@ -20,7 +20,7 @@ public class BaseModelComboBox extends ComboBox { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value != null) { - BaseModel model = (BaseModel) value; + CompletionModel model = (CompletionModel) value; setText(model.getDescription()); } return this; diff --git a/src/main/java/ee/carlrobert/codegpt/settings/SettingsComponent.java b/src/main/java/ee/carlrobert/codegpt/settings/SettingsComponent.java new file mode 100644 index 00000000..311dd54b --- /dev/null +++ b/src/main/java/ee/carlrobert/codegpt/settings/SettingsComponent.java @@ -0,0 +1,172 @@ +package ee.carlrobert.codegpt.settings; + +import com.intellij.openapi.ui.ComboBox; +import com.intellij.ui.TitledSeparator; +import com.intellij.ui.components.JBRadioButton; +import com.intellij.ui.components.JBTextField; +import com.intellij.util.ui.FormBuilder; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UI; +import ee.carlrobert.codegpt.util.SwingUtils; +import ee.carlrobert.openai.client.completion.CompletionModel; +import ee.carlrobert.openai.client.completion.chat.ChatCompletionModel; +import ee.carlrobert.openai.client.completion.text.TextCompletionModel; +import java.awt.Desktop; +import java.io.IOException; +import java.net.URISyntaxException; +import javax.swing.ButtonGroup; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.event.HyperlinkEvent; + +public class SettingsComponent { + + private final JPanel mainPanel; + private final JBTextField apiKeyField; + private final ComboBox chatCompletionBaseModelComboBox; + private final ComboBox textCompletionBaseModelComboBox; + private final JBRadioButton useChatCompletionRadioButton; + private final JBRadioButton useTextCompletionRadioButton; + + public SettingsComponent(SettingsState settings) { + apiKeyField = new JBTextField(settings.apiKey, 1); + chatCompletionBaseModelComboBox = new BaseModelComboBox( + new ChatCompletionModel[] { + ChatCompletionModel.GPT_3_5, + ChatCompletionModel.GPT_3_5_SNAPSHOT, + ChatCompletionModel.GPT_4 + }, + settings.textCompletionBaseModel); + textCompletionBaseModelComboBox = new BaseModelComboBox( + new TextCompletionModel[] { + TextCompletionModel.DAVINCI, + TextCompletionModel.CURIE, + TextCompletionModel.BABBAGE, + TextCompletionModel.ADA, + }, + settings.textCompletionBaseModel); + useChatCompletionRadioButton = new JBRadioButton("Use chat completion", settings.isChatCompletionOptionSelected); + useTextCompletionRadioButton = new JBRadioButton("Use text completion", settings.isTextCompletionOptionSelected); + mainPanel = FormBuilder.createFormBuilder() + .addComponent(new TitledSeparator("Integration Preference")) + .addVerticalGap(8) + .addComponent(createMainSelectionForm()) + .addVerticalGap(8) + .addComponentFillVertically(new JPanel(), 0) + .getPanel(); + + registerButtons(); + registerFields(); + } + + public JPanel getPanel() { + return mainPanel; + } + + public JComponent getPreferredFocusedComponent() { + return apiKeyField; + } + + public String getApiKey() { + return apiKeyField.getText(); + } + + public void setApiKey(String apiKey) { + apiKeyField.setText(apiKey); + } + + public boolean isChatCompletionOptionSelected() { + return useChatCompletionRadioButton.isSelected(); + } + + public void setUseChatCompletionSelected(boolean isSelected) { + useChatCompletionRadioButton.setSelected(isSelected); + } + + public boolean isTextCompletionOptionSelected() { + return useTextCompletionRadioButton.isSelected(); + } + + public void setUseTextCompletionSelected(boolean isSelected) { + useTextCompletionRadioButton.setSelected(isSelected); + } + + public TextCompletionModel getTextCompletionBaseModel() { + return (TextCompletionModel) textCompletionBaseModelComboBox.getSelectedItem(); + } + + public void setTextCompletionBaseModel(CompletionModel model) { + textCompletionBaseModelComboBox.setSelectedItem(model); + } + + public ChatCompletionModel getChatCompletionBaseModel() { + return (ChatCompletionModel) chatCompletionBaseModelComboBox.getSelectedItem(); + } + + public void setChatCompletionBaseModel(CompletionModel model) { + chatCompletionBaseModelComboBox.setSelectedItem(model); + } + + private JPanel createMainSelectionForm() { + var apiKeyFieldPanel = UI.PanelFactory.panel(apiKeyField) + .withLabel("API key:") + .withComment("You can find your Secret API key in your User settings.") + .withCommentHyperlinkListener(this::handleHyperlinkClicked) + .createPanel(); + apiKeyFieldPanel.setBorder(JBUI.Borders.emptyLeft(8)); + + var chatCompletionModelsPanel = SwingUtils.createPanel(chatCompletionBaseModelComboBox, "Model:", false); + chatCompletionModelsPanel.setBorder(JBUI.Borders.emptyLeft(24)); + + var textCompletionModelsPanel = SwingUtils.createPanel(textCompletionBaseModelComboBox, "Model:", false); + textCompletionModelsPanel.setBorder(JBUI.Borders.emptyLeft(24)); + + var panel = FormBuilder.createFormBuilder() + .addComponent(FormBuilder.createFormBuilder() + .addComponent(apiKeyFieldPanel) + .addComponent(UI.PanelFactory.panel(useChatCompletionRadioButton) + .withComment("OpenAI’s most advanced language model") + .createPanel()) + .addComponent(chatCompletionModelsPanel) + .addVerticalGap(8) + .addComponent(UI.PanelFactory.panel(useTextCompletionRadioButton) + .withComment("Best for high-quality texts") + .createPanel()) + .addComponent(textCompletionModelsPanel) + .getPanel()) + .getPanel(); + panel.setBorder(JBUI.Borders.emptyLeft(16)); + return panel; + } + + private void registerButtons() { + ButtonGroup completionButtonGroup = new ButtonGroup(); + completionButtonGroup.add(useChatCompletionRadioButton); + completionButtonGroup.add(useTextCompletionRadioButton); + useChatCompletionRadioButton.addActionListener(e -> { + chatCompletionBaseModelComboBox.setEnabled(true); + textCompletionBaseModelComboBox.setEnabled(false); + }); + useTextCompletionRadioButton.addActionListener(e -> { + chatCompletionBaseModelComboBox.setEnabled(false); + textCompletionBaseModelComboBox.setEnabled(true); + }); + } + + private void registerFields() { + chatCompletionBaseModelComboBox.setEnabled(useChatCompletionRadioButton.isSelected()); + textCompletionBaseModelComboBox.setEnabled(useTextCompletionRadioButton.isSelected()); + } + + private void handleHyperlinkClicked(HyperlinkEvent event) { + if (HyperlinkEvent.EventType.ACTIVATED.equals(event.getEventType())) { + if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + try { + Desktop.getDesktop().browse(event.getURL().toURI()); + } catch (IOException | URISyntaxException e) { + throw new RuntimeException("Couldn't open the browser.", e); + } + } + } + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsConfigurable.java b/src/main/java/ee/carlrobert/codegpt/settings/SettingsConfigurable.java similarity index 68% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsConfigurable.java rename to src/main/java/ee/carlrobert/codegpt/settings/SettingsConfigurable.java index d689304d..58772539 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsConfigurable.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/SettingsConfigurable.java @@ -1,7 +1,7 @@ -package ee.carlrobert.codegpt.ide.settings; +package ee.carlrobert.codegpt.settings; import com.intellij.openapi.options.Configurable; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.ConversationsState; import javax.swing.JComponent; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nullable; @@ -33,8 +33,6 @@ public class SettingsConfigurable implements Configurable { public boolean isModified() { var settings = SettingsState.getInstance(); return !settingsComponent.getApiKey().equals(settings.apiKey) || - !settingsComponent.getAccessToken().equals(settings.accessToken) || - !settingsComponent.getReverseProxyUrl().equals(settings.reverseProxyUrl) || isModelChanged(settings) || isClientChanged(settings); } @@ -46,11 +44,7 @@ public class SettingsConfigurable implements Configurable { ConversationsState.getInstance().setCurrentConversation(null); } - settings.isGPTOptionSelected = settingsComponent.isGPTOptionSelected(); - settings.isChatGPTOptionSelected = settingsComponent.isChatGPTOptionSelected(); - settings.accessToken = settingsComponent.getAccessToken(); settings.apiKey = settingsComponent.getApiKey(); - settings.reverseProxyUrl = settingsComponent.getReverseProxyUrl(); settings.chatCompletionBaseModel = settingsComponent.getChatCompletionBaseModel(); settings.isChatCompletionOptionSelected = settingsComponent.isChatCompletionOptionSelected(); settings.isTextCompletionOptionSelected = settingsComponent.isTextCompletionOptionSelected(); @@ -60,13 +54,9 @@ public class SettingsConfigurable implements Configurable { @Override public void reset() { var settings = SettingsState.getInstance(); - settingsComponent.setUseGPTOptionSelected(settings.isGPTOptionSelected); settingsComponent.setUseChatCompletionSelected(settings.isChatCompletionOptionSelected); settingsComponent.setUseTextCompletionSelected(settings.isTextCompletionOptionSelected); - settingsComponent.setUseChatGPTOptionSelected(settings.isChatGPTOptionSelected); - settingsComponent.setAccessToken(settings.accessToken); settingsComponent.setApiKey(settings.apiKey); - settingsComponent.setReverseProxyUrl(settings.reverseProxyUrl); settingsComponent.setChatCompletionBaseModel(settings.chatCompletionBaseModel); settingsComponent.setTextCompletionBaseModel(settings.textCompletionBaseModel); } @@ -77,10 +67,8 @@ public class SettingsConfigurable implements Configurable { } private boolean isClientChanged(SettingsState settings) { - return settingsComponent.isGPTOptionSelected() != settings.isGPTOptionSelected || - settingsComponent.isChatCompletionOptionSelected() != settings.isChatCompletionOptionSelected || - settingsComponent.isTextCompletionOptionSelected() != settings.isTextCompletionOptionSelected || - settingsComponent.isChatGPTOptionSelected() != settings.isChatGPTOptionSelected; + return settingsComponent.isChatCompletionOptionSelected() != settings.isChatCompletionOptionSelected || + settingsComponent.isTextCompletionOptionSelected() != settings.isTextCompletionOptionSelected; } private boolean isModelChanged(SettingsState settings) { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsState.java b/src/main/java/ee/carlrobert/codegpt/settings/SettingsState.java similarity index 67% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsState.java rename to src/main/java/ee/carlrobert/codegpt/settings/SettingsState.java index f478935f..14cef966 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/SettingsState.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/SettingsState.java @@ -1,27 +1,25 @@ -package ee.carlrobert.codegpt.ide.settings; +package ee.carlrobert.codegpt.settings; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.util.xmlb.XmlSerializerUtil; -import ee.carlrobert.codegpt.client.BaseModel; +import ee.carlrobert.openai.client.completion.CompletionModel; +import ee.carlrobert.openai.client.completion.chat.ChatCompletionModel; +import ee.carlrobert.openai.client.completion.text.TextCompletionModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @State( - name = "ee.carlrobert.codegpt.ide.settings.SettingsState", + name = "ee.carlrobert.codegpt.settings.SettingsState", storages = @Storage("CodeGPTSettings.xml") ) public class SettingsState implements PersistentStateComponent { public String apiKey = ""; - public String accessToken = ""; - public String reverseProxyUrl = ""; - public BaseModel textCompletionBaseModel = BaseModel.DAVINCI; - public BaseModel chatCompletionBaseModel = BaseModel.CHATGPT; - public boolean isGPTOptionSelected = true; - public boolean isChatGPTOptionSelected; + public CompletionModel textCompletionBaseModel = TextCompletionModel.DAVINCI; + public CompletionModel chatCompletionBaseModel = ChatCompletionModel.GPT_3_5; public boolean isChatCompletionOptionSelected = true; public boolean isTextCompletionOptionSelected; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsComponent.java b/src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsComponent.java similarity index 97% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsComponent.java rename to src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsComponent.java index bb53645c..7ae0d6f2 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsComponent.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsComponent.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.settings.advanced; +package ee.carlrobert.codegpt.settings.advanced; import com.intellij.openapi.ui.ComboBox; import com.intellij.ui.PortField; @@ -9,7 +9,7 @@ import com.intellij.ui.components.JBTextField; import com.intellij.util.ui.FormBuilder; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UI; -import ee.carlrobert.codegpt.ide.util.SwingUtils; +import ee.carlrobert.codegpt.util.SwingUtils; import java.awt.event.ItemEvent; import java.net.Proxy; import javax.swing.BoxLayout; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsConfigurable.java b/src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsConfigurable.java similarity index 98% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsConfigurable.java rename to src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsConfigurable.java index 4016d420..ac640734 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsConfigurable.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsConfigurable.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.settings.advanced; +package ee.carlrobert.codegpt.settings.advanced; import com.intellij.openapi.options.Configurable; import javax.swing.JComponent; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsState.java b/src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsState.java similarity index 89% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsState.java rename to src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsState.java index 788dcdb9..3c2ca466 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/advanced/AdvancedSettingsState.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/advanced/AdvancedSettingsState.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.settings.advanced; +package ee.carlrobert.codegpt.settings.advanced; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; @@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @State( - name = "ee.carlrobert.codegpt.ide.settings.advanced.AdvancedSettingsState", + name = "ee.carlrobert.codegpt.settings.advanced.AdvancedSettingsState", storages = @Storage("CodeGPTAdvancedSettings.xml") ) public class AdvancedSettingsState implements PersistentStateComponent { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationComponent.java b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationComponent.java similarity index 93% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationComponent.java rename to src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationComponent.java index f59392c7..b9de3179 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationComponent.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationComponent.java @@ -1,6 +1,6 @@ -package ee.carlrobert.codegpt.ide.settings.configuration; +package ee.carlrobert.codegpt.settings.configuration; -import static ee.carlrobert.codegpt.ide.action.ActionsUtil.DEFAULT_ACTIONS_ARRAY; +import static ee.carlrobert.codegpt.action.ActionsUtil.DEFAULT_ACTIONS_ARRAY; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -9,7 +9,7 @@ import com.intellij.ui.TitledSeparator; import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.table.JBTable; import com.intellij.util.ui.FormBuilder; -import ee.carlrobert.codegpt.ide.action.ActionsUtil; +import ee.carlrobert.codegpt.action.ActionsUtil; import java.awt.Dimension; import java.util.Arrays; import java.util.LinkedHashMap; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationConfigurable.java b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationConfigurable.java similarity index 92% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationConfigurable.java rename to src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationConfigurable.java index 75613f33..21b0669b 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationConfigurable.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationConfigurable.java @@ -1,7 +1,7 @@ -package ee.carlrobert.codegpt.ide.settings.configuration; +package ee.carlrobert.codegpt.settings.configuration; import com.intellij.openapi.options.Configurable; -import ee.carlrobert.codegpt.ide.action.ActionsUtil; +import ee.carlrobert.codegpt.action.ActionsUtil; import javax.swing.JComponent; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationState.java b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationState.java similarity index 83% rename from src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationState.java rename to src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationState.java index 2dc767a8..75135528 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/settings/configuration/ConfigurationState.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationState.java @@ -1,17 +1,17 @@ -package ee.carlrobert.codegpt.ide.settings.configuration; +package ee.carlrobert.codegpt.settings.configuration; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.util.xmlb.XmlSerializerUtil; -import ee.carlrobert.codegpt.ide.action.ActionsUtil; +import ee.carlrobert.codegpt.action.ActionsUtil; import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @State( - name = "ee.carlrobert.codegpt.ide.settings.configuration.ConfigurationState", + name = "ee.carlrobert.codegpt.settings.configuration.ConfigurationState", storages = @Storage("CodeGPTConfiguration.xml") ) public class ConfigurationState implements PersistentStateComponent { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ContentManagerService.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/ContentManagerService.java similarity index 96% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ContentManagerService.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/ContentManagerService.java index 6e774cb7..54b65c72 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ContentManagerService.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/ContentManagerService.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow; +package ee.carlrobert.codegpt.toolwindow; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ProjectToolWindowFactory.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/ProjectToolWindowFactory.java similarity index 87% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ProjectToolWindowFactory.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/ProjectToolWindowFactory.java index 7d1ffc27..03b24cce 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/ProjectToolWindowFactory.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/ProjectToolWindowFactory.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow; +package ee.carlrobert.codegpt.toolwindow; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -8,10 +8,10 @@ import com.intellij.ui.content.ContentManagerEvent; import com.intellij.ui.content.ContentManagerListener; import com.intellij.ui.jcef.JBCefBrowser; import ee.carlrobert.codegpt.client.ClientFactory; -import ee.carlrobert.codegpt.ide.account.AccountDetailsState; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; -import ee.carlrobert.codegpt.ide.toolwindow.chat.ChatGptToolWindow; -import ee.carlrobert.codegpt.ide.toolwindow.conversations.ConversationsToolWindow; +import ee.carlrobert.codegpt.account.AccountDetailsState; +import ee.carlrobert.codegpt.conversations.ConversationsState; +import ee.carlrobert.codegpt.toolwindow.chat.ChatGptToolWindow; +import ee.carlrobert.codegpt.toolwindow.conversations.ConversationsToolWindow; import javax.swing.JComponent; import org.jetbrains.annotations.NotNull; @@ -33,8 +33,7 @@ public class ProjectToolWindowFactory implements ToolWindowFactory, DumbAware { if ("Conversation History".equals(content.getTabName()) && content.isSelected()) { conversationsToolWindow.refresh(); } else if ("Chat".equals(content.getTabName()) && content.isSelected()) { - new ClientFactory() - .getClient() + ClientFactory.getBillingClient() .getCreditUsageAsync(creditUsage -> { var accountDetails = AccountDetailsState.getInstance(); accountDetails.totalAmountGranted = creditUsage.getTotalGranted(); diff --git a/src/main/java/ee/carlrobert/codegpt/toolwindow/ToolWindowService.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/ToolWindowService.java new file mode 100644 index 00000000..c6d5791c --- /dev/null +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/ToolWindowService.java @@ -0,0 +1,81 @@ +package ee.carlrobert.codegpt.toolwindow; + +import com.intellij.ide.ui.LafManager; +import com.intellij.ide.ui.LafManagerListener; +import com.intellij.openapi.project.Project; +import ee.carlrobert.codegpt.client.ClientFactory; +import ee.carlrobert.codegpt.client.ClientRequestFactory; +import ee.carlrobert.codegpt.client.EventListener; +import ee.carlrobert.codegpt.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.message.Message; +import ee.carlrobert.codegpt.settings.SettingsState; +import ee.carlrobert.codegpt.toolwindow.chat.ChatGptToolWindow; +import ee.carlrobert.codegpt.toolwindow.components.SyntaxTextArea; +import java.util.List; +import javax.swing.SwingWorker; +import okhttp3.sse.EventSource; +import org.jetbrains.annotations.NotNull; + +public class ToolWindowService implements LafManagerListener { + + private ChatGptToolWindow chatToolWindow; + + @Override + public void lookAndFeelChanged(@NotNull LafManager source) { + chatToolWindow.changeStyle(); + } + + public void setChatToolWindow(ChatGptToolWindow chatToolWindow) { + this.chatToolWindow = chatToolWindow; + } + + public ChatGptToolWindow getChatToolWindow() { + return chatToolWindow; + } + + public void startRequest(String prompt, SyntaxTextArea textArea, Project project) { + var conversationsState = ConversationsState.getInstance(); + var currentConversation = ConversationsState.getCurrentConversation(); + var conversation = currentConversation == null ? conversationsState.startConversation() : currentConversation; + var conversationMessage = new Message(prompt); + + new SwingWorker() { + protected Void doInBackground() { + var eventListener = new EventListener( + conversationMessage, + textArea::append, + () -> chatToolWindow.stopGenerating(prompt, textArea, project)) { + public void onMessage(String message) { + publish(message); + } + }; + + EventSource call; + var settings = SettingsState.getInstance(); + var requestFactory = new ClientRequestFactory(prompt, conversation); + if (settings.isChatCompletionOptionSelected) { + call = ClientFactory.getChatCompletionClient().stream( + requestFactory.buildChatCompletionRequest(settings), eventListener); + } else { + call = ClientFactory.getTextCompletionClient().stream( + requestFactory.buildTextCompletionRequest(settings), eventListener); + } + chatToolWindow.displayGenerateButton(call::cancel); + return null; + } + + protected void process(List chunks) { + for (String text : chunks) { + try { + textArea.append(text); + conversationMessage.setResponse(textArea.getText()); + chatToolWindow.scrollToBottom(); + } catch (Exception e) { + textArea.append("Something went wrong. Please try again later."); + throw new RuntimeException(e); + } + } + } + }.execute(); + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/ChatGptToolWindow.form b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatGptToolWindow.form similarity index 83% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/ChatGptToolWindow.form rename to src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatGptToolWindow.form index d1d375fd..c624e1b7 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/ChatGptToolWindow.form +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatGptToolWindow.form @@ -1,5 +1,5 @@ -
+ @@ -8,7 +8,7 @@ - + @@ -32,7 +32,7 @@ - + diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/ChatGptToolWindow.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatGptToolWindow.java similarity index 82% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/ChatGptToolWindow.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatGptToolWindow.java index 521e6021..cb0cb373 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/ChatGptToolWindow.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatGptToolWindow.java @@ -1,8 +1,8 @@ -package ee.carlrobert.codegpt.ide.toolwindow.chat; +package ee.carlrobert.codegpt.toolwindow.chat; -import static ee.carlrobert.codegpt.ide.util.SwingUtils.createIconLabel; -import static ee.carlrobert.codegpt.ide.util.SwingUtils.createTextPane; -import static ee.carlrobert.codegpt.ide.util.SwingUtils.justifyLeft; +import static ee.carlrobert.codegpt.util.SwingUtils.createIconLabel; +import static ee.carlrobert.codegpt.util.SwingUtils.createTextPane; +import static ee.carlrobert.codegpt.util.SwingUtils.justifyLeft; import static java.lang.String.format; import com.intellij.icons.AllIcons; @@ -15,20 +15,20 @@ import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.ui.JBColor; import com.intellij.ui.components.JBScrollPane; -import ee.carlrobert.codegpt.ide.account.AccountDetailsState; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; -import ee.carlrobert.codegpt.ide.settings.SettingsConfigurable; -import ee.carlrobert.codegpt.ide.settings.SettingsState; -import ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService; -import ee.carlrobert.codegpt.ide.toolwindow.chat.actions.CreateNewConversationAction; -import ee.carlrobert.codegpt.ide.toolwindow.chat.actions.OpenInEditorAction; -import ee.carlrobert.codegpt.ide.toolwindow.chat.actions.UsageToolbarLabelAction; -import ee.carlrobert.codegpt.ide.toolwindow.components.GenerateButton; -import ee.carlrobert.codegpt.ide.toolwindow.components.LandingView; -import ee.carlrobert.codegpt.ide.toolwindow.components.ScrollPane; -import ee.carlrobert.codegpt.ide.toolwindow.components.SyntaxTextArea; -import ee.carlrobert.codegpt.ide.toolwindow.components.TextArea; +import ee.carlrobert.codegpt.account.AccountDetailsState; +import ee.carlrobert.codegpt.conversations.Conversation; +import ee.carlrobert.codegpt.conversations.ConversationsState; +import ee.carlrobert.codegpt.settings.SettingsConfigurable; +import ee.carlrobert.codegpt.settings.SettingsState; +import ee.carlrobert.codegpt.toolwindow.ToolWindowService; +import ee.carlrobert.codegpt.toolwindow.chat.actions.CreateNewConversationAction; +import ee.carlrobert.codegpt.toolwindow.chat.actions.OpenInEditorAction; +import ee.carlrobert.codegpt.toolwindow.chat.actions.UsageToolbarLabelAction; +import ee.carlrobert.codegpt.toolwindow.components.GenerateButton; +import ee.carlrobert.codegpt.toolwindow.components.LandingView; +import ee.carlrobert.codegpt.toolwindow.components.ScrollPane; +import ee.carlrobert.codegpt.toolwindow.components.SyntaxTextArea; +import ee.carlrobert.codegpt.toolwindow.components.TextArea; import icons.Icons; import java.awt.Cursor; import java.awt.Dimension; @@ -116,7 +116,7 @@ public class ChatGptToolWindow { clearWindow(); conversation.getMessages().forEach(message -> { displayUserMessage(message.getPrompt()); - addIconLabel(Icons.DefaultImageIcon, "ChatGPT:"); + addIconLabel(Icons.DefaultImageIcon, "ChatGPT"); var textArea = new SyntaxTextArea(true, false, SyntaxConstants.SYNTAX_STYLE_MARKDOWN); textArea.setText(message.getResponse()); textArea.displayCopyButton(); @@ -129,13 +129,11 @@ public class ChatGptToolWindow { } public void sendMessage(String prompt, Project project) { - addIconLabel(Icons.DefaultImageIcon, "ChatGPT:"); + addIconLabel(Icons.DefaultImageIcon, "ChatGPT"); var settings = SettingsState.getInstance(); - if (settings.isGPTOptionSelected && settings.apiKey.isEmpty()) { + if (settings.apiKey.isEmpty()) { notifyMissingCredential(project, "API key not provided."); - } else if (settings.isChatGPTOptionSelected && settings.accessToken.isEmpty()) { - notifyMissingCredential(project, "Access token not provided."); } else { var textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN); addTextArea(textArea); diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/CreateNewConversationAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/CreateNewConversationAction.java similarity index 78% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/CreateNewConversationAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/CreateNewConversationAction.java index fb6e111a..ae8a97fb 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/CreateNewConversationAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/CreateNewConversationAction.java @@ -1,10 +1,10 @@ -package ee.carlrobert.codegpt.ide.toolwindow.chat.actions; +package ee.carlrobert.codegpt.toolwindow.chat.actions; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; -import ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService; +import ee.carlrobert.codegpt.conversations.ConversationsState; +import ee.carlrobert.codegpt.toolwindow.ToolWindowService; import org.jetbrains.annotations.NotNull; public class CreateNewConversationAction extends AnAction { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/OpenInEditorAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/OpenInEditorAction.java similarity index 94% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/OpenInEditorAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/OpenInEditorAction.java index 6e8cac6e..c5f662c0 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/OpenInEditorAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/OpenInEditorAction.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow.chat.actions; +package ee.carlrobert.codegpt.toolwindow.chat.actions; import static java.util.Objects.requireNonNull; @@ -9,7 +9,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.testFramework.LightVirtualFile; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.ConversationsState; import java.time.format.DateTimeFormatter; import java.util.stream.Collectors; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/TokenToolbarLabelAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/TokenToolbarLabelAction.java similarity index 93% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/TokenToolbarLabelAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/TokenToolbarLabelAction.java index 40e9e795..79a7d31c 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/TokenToolbarLabelAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/TokenToolbarLabelAction.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow.chat.actions; +package ee.carlrobert.codegpt.toolwindow.chat.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/UsageToolbarLabelAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/UsageToolbarLabelAction.java similarity index 90% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/UsageToolbarLabelAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/UsageToolbarLabelAction.java index ae46ca4b..a294315e 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/chat/actions/UsageToolbarLabelAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/actions/UsageToolbarLabelAction.java @@ -1,10 +1,10 @@ -package ee.carlrobert.codegpt.ide.toolwindow.chat.actions; +package ee.carlrobert.codegpt.toolwindow.chat.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.ex.ToolbarLabelAction; import com.intellij.util.ui.JBUI; -import ee.carlrobert.codegpt.ide.account.AccountDetailsState; +import ee.carlrobert.codegpt.account.AccountDetailsState; import javax.swing.JComponent; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/ComponentBorder.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/ComponentBorder.java similarity index 99% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/ComponentBorder.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/components/ComponentBorder.java index c2060e45..fe3433ae 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/ComponentBorder.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/ComponentBorder.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow.components; +package ee.carlrobert.codegpt.toolwindow.components; import java.awt.*; import javax.swing.*; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/GenerateButton.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/GenerateButton.java similarity index 93% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/GenerateButton.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/components/GenerateButton.java index 75da4d2c..712301fc 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/GenerateButton.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/GenerateButton.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow.components; +package ee.carlrobert.codegpt.toolwindow.components; import com.intellij.icons.AllIcons; import javax.swing.JButton; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/LandingView.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/LandingView.java similarity index 95% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/LandingView.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/components/LandingView.java index d4eb66d8..0b6b6b3b 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/LandingView.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/LandingView.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow.components; +package ee.carlrobert.codegpt.toolwindow.components; import static java.util.stream.Collectors.toList; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/ScrollPane.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/ScrollPane.java similarity index 94% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/ScrollPane.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/components/ScrollPane.java index a5a01bc8..1076b137 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/ScrollPane.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/ScrollPane.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow.components; +package ee.carlrobert.codegpt.toolwindow.components; import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel; import com.intellij.ui.components.JBScrollPane; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/SyntaxTextArea.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/SyntaxTextArea.java similarity index 94% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/SyntaxTextArea.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/components/SyntaxTextArea.java index cf037e72..460682d4 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/SyntaxTextArea.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/SyntaxTextArea.java @@ -1,6 +1,6 @@ -package ee.carlrobert.codegpt.ide.toolwindow.components; +package ee.carlrobert.codegpt.toolwindow.components; -import static ee.carlrobert.codegpt.ide.util.SwingUtils.createIconButton; +import static ee.carlrobert.codegpt.util.SwingUtils.createIconButton; import com.intellij.icons.AllIcons; import com.intellij.util.ui.JBFont; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/TextArea.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/TextArea.java similarity index 88% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/TextArea.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/components/TextArea.java index 376f2765..b144e90e 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/components/TextArea.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/components/TextArea.java @@ -1,7 +1,7 @@ -package ee.carlrobert.codegpt.ide.toolwindow.components; +package ee.carlrobert.codegpt.toolwindow.components; -import static ee.carlrobert.codegpt.ide.util.SwingUtils.addShiftEnterInputMap; -import static ee.carlrobert.codegpt.ide.util.SwingUtils.createIconButton; +import static ee.carlrobert.codegpt.util.SwingUtils.addShiftEnterInputMap; +import static ee.carlrobert.codegpt.util.SwingUtils.createIconButton; import com.intellij.ui.JBColor; import com.intellij.ui.components.JBTextArea; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationPanel.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationPanel.java similarity index 93% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationPanel.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationPanel.java index 300cc645..68cf2360 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationPanel.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationPanel.java @@ -1,11 +1,11 @@ -package ee.carlrobert.codegpt.ide.toolwindow.conversations; +package ee.carlrobert.codegpt.toolwindow.conversations; -import static ee.carlrobert.codegpt.ide.util.SwingUtils.justifyLeft; +import static ee.carlrobert.codegpt.util.SwingUtils.justifyLeft; import com.intellij.icons.AllIcons; import com.intellij.ui.JBColor; import com.intellij.util.ui.JBUI; -import ee.carlrobert.codegpt.ide.conversations.Conversation; +import ee.carlrobert.codegpt.conversations.Conversation; import java.awt.Cursor; import java.awt.Font; import java.awt.GridBagConstraints; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationsToolWindow.form b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationsToolWindow.form similarity index 90% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationsToolWindow.form rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationsToolWindow.form index bd3306cc..5f778b1e 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationsToolWindow.form +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationsToolWindow.form @@ -1,5 +1,5 @@ - + diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationsToolWindow.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationsToolWindow.java similarity index 65% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationsToolWindow.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationsToolWindow.java index f297c559..5eddedc4 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/ConversationsToolWindow.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/ConversationsToolWindow.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow.conversations; +package ee.carlrobert.codegpt.toolwindow.conversations; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionToolbar; @@ -7,17 +7,20 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.ui.components.JBScrollPane; -import ee.carlrobert.codegpt.client.ClientCode; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; -import ee.carlrobert.codegpt.ide.settings.SettingsState; -import ee.carlrobert.codegpt.ide.toolwindow.ContentManagerService; -import ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService; -import ee.carlrobert.codegpt.ide.toolwindow.conversations.actions.ClearAllConversationsAction; -import ee.carlrobert.codegpt.ide.toolwindow.conversations.actions.DeleteConversationAction; -import ee.carlrobert.codegpt.ide.toolwindow.conversations.actions.MoveDownAction; -import ee.carlrobert.codegpt.ide.toolwindow.conversations.actions.MoveUpAction; +import com.intellij.util.ui.JBFont; +import com.intellij.util.ui.JBUI; +import ee.carlrobert.codegpt.conversations.Conversation; +import ee.carlrobert.codegpt.conversations.ConversationsState; +import ee.carlrobert.codegpt.settings.SettingsState; +import ee.carlrobert.codegpt.toolwindow.ContentManagerService; +import ee.carlrobert.codegpt.toolwindow.ToolWindowService; +import ee.carlrobert.codegpt.toolwindow.conversations.actions.ClearAllConversationsAction; +import ee.carlrobert.codegpt.toolwindow.conversations.actions.DeleteConversationAction; +import ee.carlrobert.codegpt.toolwindow.conversations.actions.MoveDownAction; +import ee.carlrobert.codegpt.toolwindow.conversations.actions.MoveUpAction; +import ee.carlrobert.openai.client.ClientCode; import javax.swing.BoxLayout; +import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; @@ -54,9 +57,17 @@ public class ConversationsToolWindow { public void refresh() { scrollablePanel.removeAll(); - ConversationsState.getInstance() - .getSortedConversations() - .forEach(this::addContent); + + var sortedConversations = ConversationsState.getInstance().getSortedConversations(); + if (sortedConversations.isEmpty()) { + var emptyLabel = new JLabel("No conversations exist."); + emptyLabel.setFont(JBFont.h2()); + emptyLabel.setBorder(JBUI.Borders.empty(8)); + scrollablePanel.add(emptyLabel); + } else { + sortedConversations.forEach(this::addContent); + } + scrollablePanel.revalidate(); scrollablePanel.repaint(); } @@ -70,30 +81,25 @@ public class ConversationsToolWindow { .getChatToolWindow() .displayConversation(conversation); }); + mainPanel.setBackground(conversationsToolWindowContent.getBackground()); var currentConversation = ConversationsState.getCurrentConversation(); var isSelected = currentConversation != null && currentConversation.getId().equals(conversation.getId()); - mainPanel.setBackground(conversationsToolWindowContent.getBackground()); mainPanel.add(new ConversationPanel(conversation, isSelected)); + scrollablePanel.add(mainPanel); } private void changeSettings(Conversation conversation) { var settings = SettingsState.getInstance(); - var isUnofficialClient = ClientCode.UNOFFICIAL_CHATGPT.equals(conversation.getClientCode()); - settings.isChatGPTOptionSelected = isUnofficialClient; - settings.isGPTOptionSelected = !isUnofficialClient; - - if (!isUnofficialClient) { - var isChatCompletions = ClientCode.CHAT_COMPLETIONS.equals(conversation.getClientCode()); - if (isChatCompletions) { - settings.chatCompletionBaseModel = conversation.getModel(); - } else { - settings.textCompletionBaseModel = conversation.getModel(); - } - settings.isChatCompletionOptionSelected = isChatCompletions; - settings.isTextCompletionOptionSelected = !isChatCompletions; + var isChatCompletions = ClientCode.CHAT_COMPLETION.equals(conversation.getClientCode()); + if (isChatCompletions) { + settings.chatCompletionBaseModel = conversation.getModel(); + } else { + settings.textCompletionBaseModel = conversation.getModel(); } + settings.isChatCompletionOptionSelected = isChatCompletions; + settings.isTextCompletionOptionSelected = !isChatCompletions; } private void createUIComponents() { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/RootConversationPanel.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/RootConversationPanel.java similarity index 94% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/RootConversationPanel.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/RootConversationPanel.java index 9a1255bd..a1d7b104 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/RootConversationPanel.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/RootConversationPanel.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.toolwindow.conversations; +package ee.carlrobert.codegpt.toolwindow.conversations; import com.intellij.ui.JBColor; import com.intellij.util.ui.JBUI; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/ClearAllConversationsAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/ClearAllConversationsAction.java similarity index 81% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/ClearAllConversationsAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/ClearAllConversationsAction.java index ef27abcb..fb75e40f 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/ClearAllConversationsAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/ClearAllConversationsAction.java @@ -1,9 +1,9 @@ -package ee.carlrobert.codegpt.ide.toolwindow.conversations.actions; +package ee.carlrobert.codegpt.toolwindow.conversations.actions; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.ConversationsState; import org.jetbrains.annotations.NotNull; public class ClearAllConversationsAction extends AnAction { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/DeleteConversationAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/DeleteConversationAction.java similarity index 82% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/DeleteConversationAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/DeleteConversationAction.java index 780d7e6a..0b6d05a1 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/DeleteConversationAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/DeleteConversationAction.java @@ -1,9 +1,9 @@ -package ee.carlrobert.codegpt.ide.toolwindow.conversations.actions; +package ee.carlrobert.codegpt.toolwindow.conversations.actions; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.ConversationsState; import org.jetbrains.annotations.NotNull; public class DeleteConversationAction extends AnAction { diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveAction.java similarity index 79% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveAction.java index b3195c00..8af0f690 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveAction.java @@ -1,9 +1,9 @@ -package ee.carlrobert.codegpt.ide.toolwindow.conversations.actions; +package ee.carlrobert.codegpt.toolwindow.conversations.actions; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.Conversation; +import ee.carlrobert.codegpt.conversations.ConversationsState; import java.util.Optional; import javax.swing.Icon; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveDownAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveDownAction.java similarity index 74% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveDownAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveDownAction.java index 9fdce0e2..352fcc9a 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveDownAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveDownAction.java @@ -1,9 +1,9 @@ -package ee.carlrobert.codegpt.ide.toolwindow.conversations.actions; +package ee.carlrobert.codegpt.toolwindow.conversations.actions; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.Conversation; +import ee.carlrobert.codegpt.conversations.ConversationsState; import java.util.Optional; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveUpAction.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveUpAction.java similarity index 74% rename from src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveUpAction.java rename to src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveUpAction.java index a26ee480..ed77358d 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/toolwindow/conversations/actions/MoveUpAction.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/conversations/actions/MoveUpAction.java @@ -1,9 +1,9 @@ -package ee.carlrobert.codegpt.ide.toolwindow.conversations.actions; +package ee.carlrobert.codegpt.toolwindow.conversations.actions; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; -import ee.carlrobert.codegpt.ide.conversations.Conversation; -import ee.carlrobert.codegpt.ide.conversations.ConversationsState; +import ee.carlrobert.codegpt.conversations.Conversation; +import ee.carlrobert.codegpt.conversations.ConversationsState; import java.util.Optional; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/ee/carlrobert/codegpt/ide/util/SwingUtils.java b/src/main/java/ee/carlrobert/codegpt/util/SwingUtils.java similarity index 98% rename from src/main/java/ee/carlrobert/codegpt/ide/util/SwingUtils.java rename to src/main/java/ee/carlrobert/codegpt/util/SwingUtils.java index 5676c2b0..e9e653ae 100644 --- a/src/main/java/ee/carlrobert/codegpt/ide/util/SwingUtils.java +++ b/src/main/java/ee/carlrobert/codegpt/util/SwingUtils.java @@ -1,4 +1,4 @@ -package ee.carlrobert.codegpt.ide.util; +package ee.carlrobert.codegpt.util; import com.intellij.ui.JBColor; import com.intellij.util.ui.JBFont; diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index b4805d5e..eb917a48 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -81,27 +81,27 @@ - + + instance="ee.carlrobert.codegpt.settings.SettingsConfigurable"/> + instance="ee.carlrobert.codegpt.settings.configuration.ConfigurationConfigurable"/> - - - - - - - + instance="ee.carlrobert.codegpt.settings.advanced.AdvancedSettingsConfigurable"/> + + + + + + + + factoryClass="ee.carlrobert.codegpt.toolwindow.ProjectToolWindowFactory"/> messages.BasicActionsBundle