mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-19 07:54:46 +00:00
feat: support custom OpenAI-compatible service (#383)
This commit is contained in:
parent
c8bb33d9b2
commit
8507c779b1
27 changed files with 772 additions and 166 deletions
|
|
@ -37,6 +37,7 @@ import java.io.IOException;
|
|||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import okhttp3.sse.EventSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class GenerateGitCommitMessageAction extends AnAction {
|
||||
|
|
@ -102,7 +103,7 @@ public class GenerateGitCommitMessageAction extends AnAction {
|
|||
private final StringBuilder messageBuilder = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
public void onMessage(String message, EventSource eventSource) {
|
||||
messageBuilder.append(message);
|
||||
var application = ApplicationManager.getApplication();
|
||||
application.invokeLater(() ->
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ public class CallParameters {
|
|||
private final Message message;
|
||||
private final boolean retry;
|
||||
|
||||
public CallParameters(Conversation conversation, Message message) {
|
||||
this(conversation, ConversationType.DEFAULT, message, false);
|
||||
}
|
||||
|
||||
public CallParameters(
|
||||
Conversation conversation,
|
||||
ConversationType conversationType,
|
||||
|
|
|
|||
|
|
@ -26,14 +26,9 @@ import okhttp3.OkHttpClient;
|
|||
public class CompletionClientProvider {
|
||||
|
||||
public static OpenAIClient getOpenAIClient() {
|
||||
var settings = OpenAISettings.getCurrentState();
|
||||
var builder = new OpenAIClient.Builder(OpenAICredentialManager.getInstance().getCredential())
|
||||
.setOrganization(settings.getOrganization());
|
||||
var baseHost = settings.getBaseHost();
|
||||
if (baseHost != null) {
|
||||
builder.setHost(baseHost);
|
||||
}
|
||||
return builder.build(getDefaultClientBuilder());
|
||||
return new OpenAIClient.Builder(OpenAICredentialManager.getInstance().getCredential())
|
||||
.setOrganization(OpenAISettings.getCurrentState().getOrganization())
|
||||
.build(getDefaultClientBuilder());
|
||||
}
|
||||
|
||||
public static AzureClient getAzureClient() {
|
||||
|
|
@ -87,7 +82,7 @@ public class CompletionClientProvider {
|
|||
return builder.build(getDefaultClientBuilder());
|
||||
}
|
||||
|
||||
private static OkHttpClient.Builder getDefaultClientBuilder() {
|
||||
public static OkHttpClient.Builder getDefaultClientBuilder() {
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
var advancedSettings = AdvancedSettings.getCurrentState();
|
||||
var proxyHost = advancedSettings.getProxyHost();
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ public class CompletionRequestHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
public void onMessage(String message, EventSource eventSource) {
|
||||
publish(message);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import static java.lang.String.format;
|
|||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import ee.carlrobert.codegpt.CodeGPTPlugin;
|
||||
|
|
@ -14,10 +16,12 @@ import ee.carlrobert.codegpt.completions.llama.PromptTemplate;
|
|||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.credentials.CustomServiceCredentialManager;
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettings;
|
||||
import ee.carlrobert.codegpt.settings.IncludedFilesSettings;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.service.custom.CustomServiceState;
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
|
||||
import ee.carlrobert.codegpt.settings.service.you.YouSettings;
|
||||
|
|
@ -31,11 +35,16 @@ import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionMe
|
|||
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionRequest;
|
||||
import ee.carlrobert.llm.client.you.completion.YouCompletionRequest;
|
||||
import ee.carlrobert.llm.client.you.completion.YouCompletionRequestMessage;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CompletionRequestProvider {
|
||||
|
|
@ -247,4 +256,51 @@ public class CompletionRequestProvider {
|
|||
|
||||
return messages.stream().filter(Objects::nonNull).collect(toList());
|
||||
}
|
||||
|
||||
public Request buildCustomOpenAIChatCompletionRequest(
|
||||
CustomServiceState customConfiguration,
|
||||
CallParameters callParameters) {
|
||||
var requestBuilder = new Request.Builder().url(customConfiguration.getUrl().trim());
|
||||
for (var entry : customConfiguration.getHeaders().entrySet()) {
|
||||
String value = entry.getValue();
|
||||
if (value.contains("$CUSTOM_SERVICE_API_KEY")) {
|
||||
value = value.replace("$CUSTOM_SERVICE_API_KEY",
|
||||
CustomServiceCredentialManager.getInstance().getCredential());
|
||||
}
|
||||
requestBuilder.addHeader(entry.getKey(), value);
|
||||
}
|
||||
|
||||
var body = customConfiguration.getBody().entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
entry -> processEntryValue(entry.getValue(), callParameters)
|
||||
));
|
||||
|
||||
try {
|
||||
var requestBody = RequestBody.create(new ObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(body)
|
||||
.getBytes(StandardCharsets.UTF_8));
|
||||
return requestBuilder.post(requestBody).build();
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Object processEntryValue(Object value, CallParameters callParameters) {
|
||||
if (!(value instanceof String)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
String stringValue = (String) value;
|
||||
switch (stringValue.toLowerCase().trim()) {
|
||||
case "$openai_messages":
|
||||
return buildMessages(callParameters, false);
|
||||
case "true":
|
||||
case "false":
|
||||
return Boolean.parseBoolean(stringValue);
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,19 @@ import ee.carlrobert.codegpt.credentials.OpenAICredentialManager;
|
|||
import ee.carlrobert.codegpt.settings.GeneralSettings;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.azure.AzureSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.custom.CustomServiceSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
|
||||
import ee.carlrobert.llm.client.llama.completion.LlamaCompletionRequest;
|
||||
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionEventSourceListener;
|
||||
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionMessage;
|
||||
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionRequest;
|
||||
import ee.carlrobert.llm.completion.CompletionEventListener;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.sse.EventSource;
|
||||
import okhttp3.sse.EventSources;
|
||||
|
||||
@Service
|
||||
public final class CompletionRequestService {
|
||||
|
|
@ -36,6 +40,15 @@ public final class CompletionRequestService {
|
|||
return ApplicationManager.getApplication().getService(CompletionRequestService.class);
|
||||
}
|
||||
|
||||
public EventSource getCustomOpenAIChatCompletionAsync(
|
||||
Request customRequest,
|
||||
CompletionEventListener<String> eventListener) {
|
||||
var httpClient = CompletionClientProvider.getDefaultClientBuilder().build();
|
||||
return EventSources.createFactory(httpClient).newEventSource(
|
||||
customRequest,
|
||||
new OpenAIChatCompletionEventSourceListener(eventListener));
|
||||
}
|
||||
|
||||
public EventSource getChatCompletionAsync(
|
||||
CallParameters callParameters,
|
||||
boolean useContextualSearch,
|
||||
|
|
@ -44,13 +57,19 @@ public final class CompletionRequestService {
|
|||
switch (GeneralSettings.getCurrentState().getSelectedService()) {
|
||||
case OPENAI:
|
||||
var openAISettings = OpenAISettings.getCurrentState();
|
||||
var customModel = openAISettings.getCustomModel();
|
||||
return CompletionClientProvider.getOpenAIClient().getChatCompletionAsync(
|
||||
requestProvider.buildOpenAIChatCompletionRequest(
|
||||
customModel.trim().isEmpty() ? openAISettings.getModel() : customModel,
|
||||
openAISettings.getModel(),
|
||||
callParameters,
|
||||
useContextualSearch,
|
||||
openAISettings.isUsingCustomPath() ? openAISettings.getPath() : null),
|
||||
null),
|
||||
eventListener);
|
||||
case CUSTOM_OPENAI:
|
||||
var customConfiguration = CustomServiceSettings.getCurrentState();
|
||||
return getCustomOpenAIChatCompletionAsync(
|
||||
requestProvider.buildCustomOpenAIChatCompletionRequest(
|
||||
customConfiguration,
|
||||
callParameters),
|
||||
eventListener);
|
||||
case AZURE:
|
||||
var azureSettings = AzureSettings.getCurrentState();
|
||||
|
|
|
|||
|
|
@ -190,6 +190,8 @@ public final class ConversationService {
|
|||
switch (serviceType) {
|
||||
case OPENAI:
|
||||
return OpenAISettings.getCurrentState().getModel();
|
||||
case CUSTOM_OPENAI:
|
||||
return "CustomService";
|
||||
case AZURE:
|
||||
return AzureSettings.getCurrentState().getDeploymentId();
|
||||
case YOU:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package ee.carlrobert.codegpt.credentials;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.Service;
|
||||
|
||||
@Service
|
||||
public final class CustomServiceCredentialManager extends SingleCredentialManager {
|
||||
|
||||
private CustomServiceCredentialManager() {
|
||||
super("CUSTOM_SERVICE_API_KEY");
|
||||
}
|
||||
|
||||
public static CustomServiceCredentialManager getInstance() {
|
||||
return ApplicationManager.getApplication().getService(CustomServiceCredentialManager.class);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package ee.carlrobert.codegpt.settings;
|
||||
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.AZURE;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.CUSTOM_OPENAI;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.LLAMA_CPP;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.OPENAI;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.YOU;
|
||||
|
|
@ -8,13 +9,16 @@ import static java.util.stream.Collectors.toList;
|
|||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.util.SystemInfoRt;
|
||||
import com.intellij.ui.components.JBTextField;
|
||||
import com.intellij.util.ui.FormBuilder;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceSelectionForm;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import java.awt.CardLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.util.Arrays;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JComponent;
|
||||
|
|
@ -30,9 +34,12 @@ public class GeneralSettingsComponent {
|
|||
public GeneralSettingsComponent(Disposable parentDisposable, GeneralSettings settings) {
|
||||
displayNameField = new JBTextField(settings.getState().getDisplayName(), 20);
|
||||
serviceSelectionForm = new ServiceSelectionForm(parentDisposable);
|
||||
var cardLayout = new CardLayout();
|
||||
var cardLayout = new DynamicCardLayout();
|
||||
var cards = new JPanel(cardLayout);
|
||||
cards.add(serviceSelectionForm.getOpenAISettingsForm().getForm(), OPENAI.getCode());
|
||||
cards.add(
|
||||
serviceSelectionForm.getCustomConfigurationSettingsForm().getForm(),
|
||||
CUSTOM_OPENAI.getCode());
|
||||
cards.add(serviceSelectionForm.getAzureSettingsForm().getForm(), AZURE.getCode());
|
||||
cards.add(serviceSelectionForm.getYouSettingsForm(), YOU.getCode());
|
||||
cards.add(serviceSelectionForm.getLlamaSettingsForm(), LLAMA_CPP.getCode());
|
||||
|
|
@ -83,4 +90,29 @@ public class GeneralSettingsComponent {
|
|||
public void setDisplayName(String displayName) {
|
||||
displayNameField.setText(displayName);
|
||||
}
|
||||
|
||||
static class DynamicCardLayout extends CardLayout {
|
||||
|
||||
@Override
|
||||
public Dimension preferredLayoutSize(Container parent) {
|
||||
Component current = findVisibleComponent(parent);
|
||||
if (current != null) {
|
||||
Insets insets = parent.getInsets();
|
||||
Dimension preferredSize = current.getPreferredSize();
|
||||
preferredSize.width += insets.left + insets.right;
|
||||
preferredSize.height += insets.top + insets.bottom;
|
||||
return preferredSize;
|
||||
}
|
||||
return super.preferredLayoutSize(parent);
|
||||
}
|
||||
|
||||
private Component findVisibleComponent(Container parent) {
|
||||
for (Component comp : parent.getComponents()) {
|
||||
if (comp.isVisible()) {
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,13 @@ import com.intellij.openapi.util.Disposer;
|
|||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.credentials.AzureCredentialsManager;
|
||||
import ee.carlrobert.codegpt.credentials.CustomServiceCredentialManager;
|
||||
import ee.carlrobert.codegpt.credentials.LlamaCredentialManager;
|
||||
import ee.carlrobert.codegpt.credentials.OpenAICredentialManager;
|
||||
import ee.carlrobert.codegpt.settings.service.azure.AzureSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.azure.AzureSettingsForm;
|
||||
import ee.carlrobert.codegpt.settings.service.custom.CustomServiceForm;
|
||||
import ee.carlrobert.codegpt.settings.service.custom.CustomServiceSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.llama.form.LlamaSettingsForm;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
|
||||
|
|
@ -56,6 +59,8 @@ public class GeneralSettingsConfigurable implements Configurable {
|
|||
return !component.getDisplayName().equals(settings.getDisplayName())
|
||||
|| component.getSelectedService() != settings.getSelectedService()
|
||||
|| OpenAISettings.getInstance().isModified(serviceSelectionForm.getOpenAISettingsForm())
|
||||
|| CustomServiceSettings.getInstance()
|
||||
.isModified(serviceSelectionForm.getCustomConfigurationSettingsForm())
|
||||
|| AzureSettings.getInstance().isModified(serviceSelectionForm.getAzureSettingsForm())
|
||||
|| YouSettings.getInstance().isModified(serviceSelectionForm.getYouSettingsForm())
|
||||
|| LlamaSettings.getInstance().isModified(serviceSelectionForm.getLlamaSettingsForm());
|
||||
|
|
@ -70,6 +75,7 @@ public class GeneralSettingsConfigurable implements Configurable {
|
|||
var serviceSelectionForm = component.getServiceSelectionForm();
|
||||
var openAISettingsForm = serviceSelectionForm.getOpenAISettingsForm();
|
||||
applyOpenAISettings(openAISettingsForm);
|
||||
applyCustomOpenAISettings(serviceSelectionForm.getCustomConfigurationSettingsForm());
|
||||
applyAzureSettings(serviceSelectionForm.getAzureSettingsForm());
|
||||
applyYouSettings(serviceSelectionForm.getYouSettingsForm());
|
||||
applyLlamaSettings(serviceSelectionForm.getLlamaSettingsForm());
|
||||
|
|
@ -87,6 +93,16 @@ public class GeneralSettingsConfigurable implements Configurable {
|
|||
}
|
||||
}
|
||||
|
||||
private void applyOpenAISettings(OpenAISettingsForm form) {
|
||||
OpenAICredentialManager.getInstance().setCredential(form.getApiKey());
|
||||
OpenAISettings.getInstance().loadState(form.getCurrentState());
|
||||
}
|
||||
|
||||
private void applyCustomOpenAISettings(CustomServiceForm form) {
|
||||
CustomServiceCredentialManager.getInstance().setCredential(form.getApiKey());
|
||||
CustomServiceSettings.getInstance().loadState(form.getCurrentState());
|
||||
}
|
||||
|
||||
private void applyLlamaSettings(LlamaSettingsForm form) {
|
||||
LlamaCredentialManager.getInstance()
|
||||
.setCredential(form.getLlamaServerPreferencesForm().getApiKey());
|
||||
|
|
@ -109,12 +125,7 @@ public class GeneralSettingsConfigurable implements Configurable {
|
|||
var settings = GeneralSettings.getCurrentState();
|
||||
component.setDisplayName(settings.getDisplayName());
|
||||
component.setSelectedService(settings.getSelectedService());
|
||||
|
||||
var serviceSelectionForm = component.getServiceSelectionForm();
|
||||
serviceSelectionForm.getOpenAISettingsForm().resetForm();
|
||||
serviceSelectionForm.getAzureSettingsForm().resetForm();
|
||||
serviceSelectionForm.getLlamaSettingsForm().resetForm();
|
||||
serviceSelectionForm.getYouSettingsForm().resetForm();
|
||||
component.getServiceSelectionForm().resetForms();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -125,11 +136,6 @@ public class GeneralSettingsConfigurable implements Configurable {
|
|||
component = null;
|
||||
}
|
||||
|
||||
private void applyOpenAISettings(OpenAISettingsForm form) {
|
||||
OpenAICredentialManager.getInstance().setCredential(form.getApiKey());
|
||||
OpenAISettings.getInstance().loadState(form.getCurrentState());
|
||||
}
|
||||
|
||||
private void resetActiveTab() {
|
||||
ConversationsState.getInstance().setCurrentConversation(null);
|
||||
var project = ApplicationUtil.findCurrentProject();
|
||||
|
|
|
|||
|
|
@ -3,23 +3,27 @@ package ee.carlrobert.codegpt.settings.service;
|
|||
import com.intellij.openapi.Disposable;
|
||||
import ee.carlrobert.codegpt.settings.service.azure.AzureSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.azure.AzureSettingsForm;
|
||||
import ee.carlrobert.codegpt.settings.service.custom.CustomServiceForm;
|
||||
import ee.carlrobert.codegpt.settings.service.custom.CustomServiceSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.llama.form.LlamaSettingsForm;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettingsForm;
|
||||
import ee.carlrobert.codegpt.settings.service.you.YouSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.you.YouSettingsForm;
|
||||
import ee.carlrobert.codegpt.settings.service.you.YouSettingsState;
|
||||
|
||||
public class ServiceSelectionForm {
|
||||
|
||||
private final OpenAISettingsForm openAISettingsForm;
|
||||
private final CustomServiceForm customServiceForm;
|
||||
private final AzureSettingsForm azureSettingsForm;
|
||||
private final LlamaSettingsForm llamaSettingsForm;
|
||||
private final YouSettingsForm youSettingsForm;
|
||||
|
||||
public ServiceSelectionForm(Disposable parentDisposable) {
|
||||
openAISettingsForm = new OpenAISettingsForm(OpenAISettings.getCurrentState());
|
||||
customServiceForm = new CustomServiceForm(
|
||||
CustomServiceSettings.getCurrentState());
|
||||
azureSettingsForm = new AzureSettingsForm(AzureSettings.getCurrentState());
|
||||
youSettingsForm = new YouSettingsForm(YouSettings.getCurrentState(), parentDisposable);
|
||||
llamaSettingsForm = new LlamaSettingsForm(LlamaSettings.getCurrentState());
|
||||
|
|
@ -29,6 +33,10 @@ public class ServiceSelectionForm {
|
|||
return openAISettingsForm;
|
||||
}
|
||||
|
||||
public CustomServiceForm getCustomConfigurationSettingsForm() {
|
||||
return customServiceForm;
|
||||
}
|
||||
|
||||
public AzureSettingsForm getAzureSettingsForm() {
|
||||
return azureSettingsForm;
|
||||
}
|
||||
|
|
@ -40,4 +48,12 @@ public class ServiceSelectionForm {
|
|||
public LlamaSettingsForm getLlamaSettingsForm() {
|
||||
return llamaSettingsForm;
|
||||
}
|
||||
|
||||
public void resetForms() {
|
||||
openAISettingsForm.resetForm();
|
||||
customServiceForm.resetForm();
|
||||
azureSettingsForm.resetForm();
|
||||
youSettingsForm.resetForm();
|
||||
llamaSettingsForm.resetForm();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package ee.carlrobert.codegpt.settings.service;
|
|||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
|
||||
public enum ServiceType {
|
||||
OPENAI("OPENAI", CodeGPTBundle.get("service.openai.title"), "chat.completion"),
|
||||
AZURE("AZURE", CodeGPTBundle.get("service.azure.title"), "azure.chat.completion"),
|
||||
YOU("YOU", CodeGPTBundle.get("service.you.title"), "you.chat.completion"),
|
||||
LLAMA_CPP("LLAMA_CPP", CodeGPTBundle.get("service.llama.title"), "llama.chat.completion");
|
||||
OPENAI("OPENAI", "service.openai.title", "chat.completion"),
|
||||
CUSTOM_OPENAI("CUSTOM_OPENAI", "service.custom.openai.title", "custom.openai.chat.completion"),
|
||||
AZURE("AZURE", "service.azure.title", "azure.chat.completion"),
|
||||
YOU("YOU", "service.you.title", "you.chat.completion"),
|
||||
LLAMA_CPP("LLAMA_CPP", "service.llama.title", "llama.chat.completion");
|
||||
|
||||
private final String code;
|
||||
private final String label;
|
||||
private final String completionCode;
|
||||
|
||||
ServiceType(String code, String label, String completionCode) {
|
||||
ServiceType(String code, String messageKey, String completionCode) {
|
||||
this.code = code;
|
||||
this.label = label;
|
||||
this.label = CodeGPTBundle.get(messageKey);
|
||||
this.completionCode = completionCode;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,175 @@
|
|||
package ee.carlrobert.codegpt.settings.service.custom;
|
||||
|
||||
import static ee.carlrobert.codegpt.ui.UIUtil.withEmptyLeftBorder;
|
||||
|
||||
import com.intellij.icons.AllIcons.General;
|
||||
import com.intellij.ide.HelpTooltip;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.ui.EnumComboBoxModel;
|
||||
import com.intellij.ui.TitledSeparator;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBPasswordField;
|
||||
import com.intellij.ui.components.JBTextField;
|
||||
import com.intellij.util.ui.FormBuilder;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.completions.CallParameters;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestProvider;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestService;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.credentials.CustomServiceCredentialManager;
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil;
|
||||
import ee.carlrobert.codegpt.ui.UIUtil;
|
||||
import ee.carlrobert.llm.client.openai.completion.ErrorDetails;
|
||||
import ee.carlrobert.llm.completion.CompletionEventListener;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import okhttp3.sse.EventSource;
|
||||
|
||||
public class CustomServiceForm {
|
||||
|
||||
private final JBPasswordField apiKeyField;
|
||||
private final JBTextField urlField;
|
||||
private final CustomServiceFormTabbedPane tabbedPane;
|
||||
private final JButton testConnectionButton;
|
||||
private final JBLabel templateHelpText;
|
||||
private final ComboBox<CustomServiceTemplate> templateComboBox;
|
||||
|
||||
public CustomServiceForm(CustomServiceState settings) {
|
||||
apiKeyField = new JBPasswordField();
|
||||
apiKeyField.setColumns(30);
|
||||
apiKeyField.setText(CustomServiceCredentialManager.getInstance().getCredential());
|
||||
urlField = new JBTextField(settings.getUrl(), 30);
|
||||
tabbedPane = new CustomServiceFormTabbedPane(settings);
|
||||
testConnectionButton = new JButton(CodeGPTBundle.get(
|
||||
"settingsConfigurable.service.custom.openai.testConnection.label"));
|
||||
testConnectionButton.addActionListener(e -> testConnection(getCurrentState()));
|
||||
templateHelpText = new JBLabel(General.ContextHelp);
|
||||
templateComboBox = new ComboBox<>(
|
||||
new EnumComboBoxModel<>(CustomServiceTemplate.class));
|
||||
templateComboBox.setSelectedItem(settings.getTemplate());
|
||||
templateComboBox.addItemListener(e -> {
|
||||
var template = (CustomServiceTemplate) e.getItem();
|
||||
updateTemplateHelpTextTooltip(template);
|
||||
urlField.setText(template.getUrl());
|
||||
tabbedPane.setHeaders(template.getHeaders());
|
||||
tabbedPane.setBody(template.getBody());
|
||||
});
|
||||
updateTemplateHelpTextTooltip(settings.getTemplate());
|
||||
}
|
||||
|
||||
public JPanel getForm() {
|
||||
var urlPanel = new JPanel(new BorderLayout(8, 0));
|
||||
urlPanel.add(urlField, BorderLayout.CENTER);
|
||||
urlPanel.add(testConnectionButton, BorderLayout.EAST);
|
||||
|
||||
var templateComboBoxWrapper = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
|
||||
templateComboBoxWrapper.add(templateComboBox);
|
||||
templateComboBoxWrapper.add(Box.createHorizontalStrut(8));
|
||||
templateComboBoxWrapper.add(templateHelpText);
|
||||
|
||||
var form = FormBuilder.createFormBuilder()
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.custom.openai.presetTemplate.label"),
|
||||
templateComboBoxWrapper)
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("settingsConfigurable.shared.apiKey.label"),
|
||||
apiKeyField)
|
||||
.addComponentToRightColumn(
|
||||
UIUtil.createComment("settingsConfigurable.service.custom.openai.apiKey.comment"))
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.custom.openai.url.label"),
|
||||
urlPanel)
|
||||
.addComponent(tabbedPane)
|
||||
.getPanel();
|
||||
|
||||
return FormBuilder.createFormBuilder()
|
||||
.addComponent(new TitledSeparator(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.openai.configuration.title")))
|
||||
.addComponent(withEmptyLeftBorder(form))
|
||||
.addComponentFillVertically(new JPanel(), 0)
|
||||
.getPanel();
|
||||
}
|
||||
|
||||
public @Nullable String getApiKey() {
|
||||
var apiKey = new String(apiKeyField.getPassword());
|
||||
return apiKey.isEmpty() ? null : apiKey;
|
||||
}
|
||||
|
||||
public CustomServiceState getCurrentState() {
|
||||
var state = new CustomServiceState();
|
||||
state.setUrl(urlField.getText());
|
||||
state.setTemplate(templateComboBox.getItem());
|
||||
state.setHeaders(tabbedPane.getHeaders());
|
||||
state.setBody(tabbedPane.getBody());
|
||||
return state;
|
||||
}
|
||||
|
||||
public void resetForm() {
|
||||
var state = CustomServiceSettings.getCurrentState();
|
||||
apiKeyField.setText(CustomServiceCredentialManager.getInstance().getCredential());
|
||||
urlField.setText(state.getUrl());
|
||||
templateComboBox.setSelectedItem(state.getTemplate());
|
||||
tabbedPane.setHeaders(state.getHeaders());
|
||||
tabbedPane.setBody(state.getBody());
|
||||
}
|
||||
|
||||
private void updateTemplateHelpTextTooltip(CustomServiceTemplate template) {
|
||||
templateHelpText.setToolTipText(null);
|
||||
try {
|
||||
new HelpTooltip()
|
||||
.setTitle(template.getName())
|
||||
.setBrowserLink(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.custom.openai.linkToDocs"),
|
||||
new URL(template.getDocsUrl()))
|
||||
.installOn(templateHelpText);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void testConnection(CustomServiceState customConfiguration) {
|
||||
var conversation = new Conversation();
|
||||
var request = new CompletionRequestProvider(conversation)
|
||||
.buildCustomOpenAIChatCompletionRequest(
|
||||
customConfiguration,
|
||||
new CallParameters(conversation, new Message("Hello!")));
|
||||
CompletionRequestService.getInstance()
|
||||
.getCustomOpenAIChatCompletionAsync(request, new TestConnectionEventListener());
|
||||
}
|
||||
|
||||
class TestConnectionEventListener implements CompletionEventListener<String> {
|
||||
|
||||
@Override
|
||||
public void onMessage(String value, EventSource eventSource) {
|
||||
if (value != null && !value.isEmpty()) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
OverlayUtil.showBalloon(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.custom.openai.connectionSuccess"),
|
||||
MessageType.INFO,
|
||||
testConnectionButton);
|
||||
eventSource.cancel();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorDetails error, Throwable ex) {
|
||||
SwingUtilities.invokeLater(() ->
|
||||
OverlayUtil.showBalloon(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.custom.openai.connectionFailed")
|
||||
+ "\n\n"
|
||||
+ error.getMessage(),
|
||||
MessageType.ERROR,
|
||||
testConnectionButton));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package ee.carlrobert.codegpt.settings.service.custom;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
import com.intellij.ui.ToolbarDecorator;
|
||||
import com.intellij.ui.components.JBTabbedPane;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
|
||||
class CustomServiceFormTabbedPane extends JBTabbedPane {
|
||||
|
||||
private final JBTable headersTable;
|
||||
private final JBTable bodyTable;
|
||||
|
||||
CustomServiceFormTabbedPane(CustomServiceState customConfiguration) {
|
||||
headersTable = new JBTable(
|
||||
new DefaultTableModel(toArray(customConfiguration.getHeaders()),
|
||||
new Object[]{"Key", "Value"}));
|
||||
bodyTable = new JBTable(
|
||||
new DefaultTableModel(toArray(customConfiguration.getBody()),
|
||||
new Object[]{"Key", "Value"}));
|
||||
|
||||
setTabComponentInsets(JBUI.insetsTop(8));
|
||||
addTab("Headers", createTablePanel(headersTable));
|
||||
addTab("Body", createTablePanel(bodyTable));
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
headersTable.setEnabled(enabled);
|
||||
bodyTable.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public void setHeaders(Map<String, String> headers) {
|
||||
setTableData(headersTable, headers);
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return getTableData(headersTable).entrySet().stream()
|
||||
.filter(entry -> entry.getKey() != null && entry.getValue() != null)
|
||||
.collect(toMap(Entry::getKey, entry -> (String) entry.getValue()));
|
||||
}
|
||||
|
||||
public void setBody(Map<String, ?> body) {
|
||||
setTableData(bodyTable, body);
|
||||
}
|
||||
|
||||
public Map<String, ?> getBody() {
|
||||
return getTableData(bodyTable);
|
||||
}
|
||||
|
||||
private void setTableData(JBTable table, Map<String, ?> values) {
|
||||
DefaultTableModel model = (DefaultTableModel) table.getModel();
|
||||
model.setRowCount(0);
|
||||
|
||||
for (var entry : values.entrySet()) {
|
||||
model.addRow(new Object[]{entry.getKey(), entry.getValue()});
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> getTableData(JBTable table) {
|
||||
var model = (DefaultTableModel) table.getModel();
|
||||
var data = new HashMap<String, Object>();
|
||||
for (int i = 0; i < model.getRowCount(); i++) {
|
||||
var key = (String) model.getValueAt(i, 0);
|
||||
data.put(key, model.getValueAt(i, 1));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static Object[][] toArray(Map<?, ?> actionsMap) {
|
||||
return actionsMap.entrySet()
|
||||
.stream()
|
||||
.map((entry) -> new Object[]{entry.getKey(), entry.getValue()})
|
||||
.collect(toList())
|
||||
.toArray(new Object[0][0]);
|
||||
}
|
||||
|
||||
private JPanel createTablePanel(JBTable table) {
|
||||
return ToolbarDecorator.createDecorator(table)
|
||||
.setAddAction(anActionButton ->
|
||||
((DefaultTableModel) table.getModel()).addRow(new Object[]{"", null}))
|
||||
.setRemoveAction(anActionButton ->
|
||||
((DefaultTableModel) table.getModel()).removeRow(table.getSelectedRow()))
|
||||
.disableUpAction()
|
||||
.disableDownAction()
|
||||
.createPanel();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package ee.carlrobert.codegpt.settings.service.custom;
|
||||
|
||||
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 ee.carlrobert.codegpt.credentials.CustomServiceCredentialManager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@State(
|
||||
name = "CodeGPT_CustomServiceSettings",
|
||||
storages = @Storage("CodeGPT_CustomServiceSettings.xml"))
|
||||
public class CustomServiceSettings implements PersistentStateComponent<CustomServiceState> {
|
||||
|
||||
private CustomServiceState state = new CustomServiceState();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CustomServiceState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(@NotNull CustomServiceState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public static CustomServiceState getCurrentState() {
|
||||
return getInstance().getState();
|
||||
}
|
||||
|
||||
public static CustomServiceSettings getInstance() {
|
||||
return ApplicationManager.getApplication().getService(CustomServiceSettings.class);
|
||||
}
|
||||
|
||||
public boolean isModified(CustomServiceForm form) {
|
||||
return !form.getCurrentState().equals(state)
|
||||
|| !StringUtils.equals(
|
||||
form.getApiKey(),
|
||||
CustomServiceCredentialManager.getInstance().getCredential());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package ee.carlrobert.codegpt.settings.service.custom;
|
||||
|
||||
import static ee.carlrobert.codegpt.settings.service.custom.CustomServiceTemplate.OPENAI;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CustomServiceState {
|
||||
|
||||
private String url = OPENAI.getUrl();
|
||||
private Map<String, String> headers = OPENAI.getHeaders();
|
||||
private Map<String, ?> body = OPENAI.getBody();
|
||||
private CustomServiceTemplate template = OPENAI;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public Map<String, ?> getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(Map<String, ?> body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public CustomServiceTemplate getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
public void setTemplate(CustomServiceTemplate template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
CustomServiceState that = (CustomServiceState) o;
|
||||
return Objects.equals(url, that.url)
|
||||
&& Objects.equals(headers, that.headers)
|
||||
&& Objects.equals(body, that.body)
|
||||
&& template == that.template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(url, headers, body, template);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
package ee.carlrobert.codegpt.settings.service.custom;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum CustomServiceTemplate {
|
||||
|
||||
// Cloud providers
|
||||
ANYSCALE(
|
||||
"Anyscale",
|
||||
"https://docs.endpoints.anyscale.com/",
|
||||
"https://api.endpoints.anyscale.com/v1/chat/completions",
|
||||
getDefaultHeadersWithAuthentication(),
|
||||
getDefaultBodyParams(Map.of(
|
||||
"model", "mistralai/Mixtral-8x7B-Instruct-v0.1",
|
||||
"max_tokens", 1024))),
|
||||
AZURE(
|
||||
"Azure OpenAI",
|
||||
"https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#chat-completions",
|
||||
"https://{your-resource-name}.openai.azure.com/openai/deployments/{deployment-id}/chat/completions?api-version=2023-05-15",
|
||||
getDefaultHeaders("api-key", "$CUSTOM_SERVICE_API_KEY"),
|
||||
getDefaultBodyParams(Map.of())),
|
||||
DEEP_INFRA(
|
||||
"DeepInfra",
|
||||
"https://deepinfra.com/docs/advanced/openai_api",
|
||||
"https://api.deepinfra.com/v1/openai/chat/completions",
|
||||
getDefaultHeadersWithAuthentication(),
|
||||
getDefaultBodyParams(Map.of(
|
||||
"model", "meta-llama/Llama-2-70b-chat-hf",
|
||||
"max_tokens", 1024))),
|
||||
FIREWORKS(
|
||||
"Fireworks",
|
||||
"https://readme.fireworks.ai/reference/createchatcompletion",
|
||||
"https://api.fireworks.ai/inference/v1/chat/completions",
|
||||
getDefaultHeadersWithAuthentication(),
|
||||
getDefaultBodyParams(Map.of(
|
||||
"model", "accounts/fireworks/models/llama-v2-7b-chat",
|
||||
"max_tokens", 1024))),
|
||||
GROQ(
|
||||
"Groq",
|
||||
"https://docs.api.groq.com/md/openai.oas.html",
|
||||
"https://api.groq.com/openai/v1/chat/completions",
|
||||
getDefaultHeadersWithAuthentication(),
|
||||
getDefaultBodyParams(Map.of(
|
||||
"model", "codellama-34b",
|
||||
"max_tokens", 1024))),
|
||||
OPENAI(
|
||||
"OpenAI",
|
||||
"https://platform.openai.com/docs/api-reference/chat",
|
||||
"https://api.openai.com/v1/chat/completions",
|
||||
getDefaultHeaders("Authorization", "Bearer $CUSTOM_SERVICE_API_KEY"),
|
||||
getDefaultBodyParams(Map.of(
|
||||
"model", "gpt-4",
|
||||
"max_tokens", 1024))),
|
||||
PERPLEXITY(
|
||||
"Perplexity AI",
|
||||
"https://docs.perplexity.ai/reference/post_chat_completions",
|
||||
"https://api.perplexity.ai/chat/completions",
|
||||
getDefaultHeadersWithAuthentication(),
|
||||
getDefaultBodyParams(Map.of(
|
||||
"model", "codellama",
|
||||
"max_tokens", 1024))),
|
||||
TOGETHER(
|
||||
"Together AI",
|
||||
"https://docs.together.ai/docs/openai-api-compatibility",
|
||||
"https://api.together.xyz/v1/chat/completions",
|
||||
getDefaultHeaders("Authorization", "Bearer $CUSTOM_SERVICE_API_KEY"),
|
||||
getDefaultBodyParams(Map.of(
|
||||
"model", "deepseek-ai/deepseek-coder-33b-instruct",
|
||||
"max_tokens", 1024))),
|
||||
|
||||
// Local providers
|
||||
OLLAMA(
|
||||
"Ollama",
|
||||
"https://github.com/ollama/ollama/blob/main/docs/openai.md",
|
||||
"http://localhost:11434/v1/chat/completions",
|
||||
getDefaultHeaders(),
|
||||
getDefaultBodyParams(Map.of("model", "codellama"))),
|
||||
LLAMA_CPP(
|
||||
"LLaMA C/C++",
|
||||
"https://github.com/ggerganov/llama.cpp/blob/master/examples/server/README.md",
|
||||
"http://localhost:8080/v1/chat/completions",
|
||||
getDefaultHeaders(),
|
||||
getDefaultBodyParams(Map.of()));
|
||||
|
||||
private final String name;
|
||||
private final String docsUrl;
|
||||
private final String url;
|
||||
private final Map<String, String> headers;
|
||||
private final Map<String, ?> body;
|
||||
|
||||
CustomServiceTemplate(
|
||||
String name,
|
||||
String docsUrl,
|
||||
String url,
|
||||
Map<String, String> headers,
|
||||
Map<String, ?> body) {
|
||||
this.name = name;
|
||||
this.docsUrl = docsUrl;
|
||||
this.url = url;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDocsUrl() {
|
||||
return docsUrl;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public Map<String, ?> getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private static Map<String, String> getDefaultHeadersWithAuthentication() {
|
||||
return getDefaultHeaders("Authorization", "Bearer $CUSTOM_SERVICE_API_KEY");
|
||||
}
|
||||
|
||||
private static Map<String, String> getDefaultHeaders() {
|
||||
return getDefaultHeaders(Map.of());
|
||||
}
|
||||
|
||||
private static Map<String, String> getDefaultHeaders(String key, String value) {
|
||||
return getDefaultHeaders(Map.of(key, value));
|
||||
}
|
||||
|
||||
private static Map<String, String> getDefaultHeaders(Map<String, String> additionalHeaders) {
|
||||
var defaultHeaders = new HashMap<>(Map.of(
|
||||
"Content-Type", "application/json",
|
||||
"X-LLM-Application-Tag", "codegpt"));
|
||||
defaultHeaders.putAll(additionalHeaders);
|
||||
return defaultHeaders;
|
||||
}
|
||||
|
||||
private static Map<String, ?> getDefaultBodyParams(Map<String, ?> additionalParams) {
|
||||
var defaultParams = new HashMap<String, Object>(Map.of(
|
||||
"stream", true,
|
||||
"messages", "$OPENAI_MESSAGES",
|
||||
"temperature", 0.1));
|
||||
defaultParams.putAll(additionalParams);
|
||||
return defaultParams;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package ee.carlrobert.codegpt.settings.service.openai;
|
|||
import static ee.carlrobert.codegpt.ui.UIUtil.withEmptyLeftBorder;
|
||||
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.EnumComboBoxModel;
|
||||
import com.intellij.ui.TitledSeparator;
|
||||
import com.intellij.ui.components.JBPasswordField;
|
||||
|
|
@ -16,15 +15,10 @@ import ee.carlrobert.codegpt.ui.UIUtil;
|
|||
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OpenAISettingsForm {
|
||||
|
||||
private final JBPasswordField apiKeyField;
|
||||
private final JBTextField customModelField;
|
||||
private final JBTextField baseHostField;
|
||||
private final JBTextField pathField;
|
||||
private final JBTextField organizationField;
|
||||
private final ComboBox<OpenAIChatCompletionModel> completionModelComboBox;
|
||||
|
||||
|
|
@ -32,64 +26,34 @@ public class OpenAISettingsForm {
|
|||
apiKeyField = new JBPasswordField();
|
||||
apiKeyField.setColumns(30);
|
||||
apiKeyField.setText(OpenAICredentialManager.getInstance().getCredential());
|
||||
organizationField = new JBTextField(settings.getOrganization(), 30);
|
||||
completionModelComboBox = new ComboBox<>(
|
||||
new EnumComboBoxModel<>(OpenAIChatCompletionModel.class));
|
||||
completionModelComboBox.setEnabled(settings.getCustomModel().isEmpty());
|
||||
completionModelComboBox.setSelectedItem(
|
||||
OpenAIChatCompletionModel.findByCode(settings.getModel()));
|
||||
customModelField = new JBTextField(settings.getCustomModel(), 20);
|
||||
customModelField.getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(@NotNull DocumentEvent e) {
|
||||
completionModelComboBox.setEnabled(customModelField.getText().isEmpty());
|
||||
}
|
||||
});
|
||||
baseHostField = new JBTextField(settings.getBaseHost(), 30);
|
||||
pathField = new JBTextField(settings.getPath(), 30);
|
||||
organizationField = new JBTextField(settings.getOrganization(), 30);
|
||||
}
|
||||
|
||||
public JPanel getForm() {
|
||||
var requestConfigurationPanel = UI.PanelFactory.grid()
|
||||
.add(UI.PanelFactory.panel(completionModelComboBox)
|
||||
.withLabel(CodeGPTBundle.get(
|
||||
"settingsConfigurable.shared.model.label"))
|
||||
.resizeX(false))
|
||||
.add(UI.PanelFactory.panel(customModelField)
|
||||
.withLabel(CodeGPTBundle.get(
|
||||
"settingsConfigurable.service.openai.customModel.label"))
|
||||
.resizeX(false))
|
||||
var configurationGrid = UI.PanelFactory.grid()
|
||||
.add(UI.PanelFactory.panel(apiKeyField)
|
||||
.withLabel(CodeGPTBundle.get("settingsConfigurable.shared.apiKey.label"))
|
||||
.resizeX(false)
|
||||
.withComment(CodeGPTBundle.get("settingsConfigurable.service.openai.apiKey.comment"))
|
||||
.withCommentHyperlinkListener(UIUtil::handleHyperlinkClicked))
|
||||
.add(UI.PanelFactory.panel(organizationField)
|
||||
.withLabel(CodeGPTBundle.get(
|
||||
"settingsConfigurable.service.openai.organization.label"))
|
||||
.withLabel(CodeGPTBundle.get("settingsConfigurable.service.openai.organization.label"))
|
||||
.resizeX(false)
|
||||
.withComment(CodeGPTBundle.get(
|
||||
"settingsConfigurable.section.openai.organization.comment")))
|
||||
.add(UI.PanelFactory.panel(baseHostField)
|
||||
.withLabel(CodeGPTBundle.get(
|
||||
"settingsConfigurable.shared.baseHost.label"))
|
||||
.add(UI.PanelFactory.panel(completionModelComboBox)
|
||||
.withLabel(CodeGPTBundle.get("settingsConfigurable.shared.model.label"))
|
||||
.resizeX(false))
|
||||
.add(UI.PanelFactory.panel(pathField)
|
||||
.withLabel(CodeGPTBundle.get(
|
||||
"settingsConfigurable.shared.path.label"))
|
||||
.resizeX(false))
|
||||
.createPanel();
|
||||
|
||||
var apiKeyFieldPanel = UI.PanelFactory.panel(apiKeyField)
|
||||
.withLabel(CodeGPTBundle.get("settingsConfigurable.shared.apiKey.label"))
|
||||
.resizeX(false)
|
||||
.withComment(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.openai.apiKey.comment"))
|
||||
.withCommentHyperlinkListener(UIUtil::handleHyperlinkClicked)
|
||||
.createPanel();
|
||||
|
||||
return FormBuilder.createFormBuilder()
|
||||
.addComponent(new TitledSeparator(
|
||||
CodeGPTBundle.get("settingsConfigurable.shared.authentication.title")))
|
||||
.addComponent(withEmptyLeftBorder(apiKeyFieldPanel))
|
||||
.addComponent(new TitledSeparator(
|
||||
CodeGPTBundle.get("settingsConfigurable.shared.requestConfiguration.title")))
|
||||
.addComponent(withEmptyLeftBorder(requestConfigurationPanel))
|
||||
CodeGPTBundle.get("settingsConfigurable.service.openai.configuration.title")))
|
||||
.addComponent(withEmptyLeftBorder(configurationGrid))
|
||||
.addComponentFillVertically(new JPanel(), 0)
|
||||
.getPanel();
|
||||
}
|
||||
|
|
@ -108,10 +72,7 @@ public class OpenAISettingsForm {
|
|||
public OpenAISettingsState getCurrentState() {
|
||||
var state = new OpenAISettingsState();
|
||||
state.setModel(getModel());
|
||||
state.setCustomModel(customModelField.getText());
|
||||
state.setOrganization(organizationField.getText());
|
||||
state.setBaseHost(baseHostField.getText());
|
||||
state.setPath(pathField.getText());
|
||||
return state;
|
||||
}
|
||||
|
||||
|
|
@ -120,9 +81,6 @@ public class OpenAISettingsForm {
|
|||
apiKeyField.setText(OpenAICredentialManager.getInstance().getCredential());
|
||||
completionModelComboBox.setSelectedItem(
|
||||
OpenAIChatCompletionModel.findByCode(state.getModel()));
|
||||
customModelField.setText(state.getCustomModel());
|
||||
organizationField.setText(state.getOrganization());
|
||||
baseHostField.setText(state.getBaseHost());
|
||||
pathField.setText(state.getPath());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,17 +5,8 @@ import java.util.Objects;
|
|||
|
||||
public class OpenAISettingsState {
|
||||
|
||||
private static final String BASE_PATH = "/v1/chat/completions";
|
||||
|
||||
private String organization = "";
|
||||
private String baseHost = "https://api.openai.com";
|
||||
private String path = BASE_PATH;
|
||||
private String model = OpenAIChatCompletionModel.GPT_3_5.getCode();
|
||||
private String customModel = "";
|
||||
|
||||
public boolean isUsingCustomPath() {
|
||||
return !BASE_PATH.equals(path);
|
||||
}
|
||||
private String model = OpenAIChatCompletionModel.GPT_3_5_0125_16k.getCode();
|
||||
|
||||
public String getOrganization() {
|
||||
return organization;
|
||||
|
|
@ -25,22 +16,6 @@ public class OpenAISettingsState {
|
|||
this.organization = organization;
|
||||
}
|
||||
|
||||
public String getBaseHost() {
|
||||
return baseHost;
|
||||
}
|
||||
|
||||
public void setBaseHost(String openAIBaseHost) {
|
||||
this.baseHost = openAIBaseHost;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
|
@ -49,14 +24,6 @@ public class OpenAISettingsState {
|
|||
this.model = model;
|
||||
}
|
||||
|
||||
public String getCustomModel() {
|
||||
return customModel;
|
||||
}
|
||||
|
||||
public void setCustomModel(String customModel) {
|
||||
this.customModel = customModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
|
@ -66,15 +33,11 @@ public class OpenAISettingsState {
|
|||
return false;
|
||||
}
|
||||
OpenAISettingsState that = (OpenAISettingsState) o;
|
||||
return Objects.equals(organization, that.organization)
|
||||
&& Objects.equals(baseHost, that.baseHost)
|
||||
&& Objects.equals(path, that.path)
|
||||
&& Objects.equals(model, that.model)
|
||||
&& Objects.equals(customModel, that.customModel);
|
||||
return Objects.equals(organization, that.organization) && Objects.equals(model, that.model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(organization, baseHost, path, model, customModel);
|
||||
return Objects.hash(organization, model);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ 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 ee.carlrobert.codegpt.credentials.YouCredentialManager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@State(name = "CodeGPT_YouSettings", storages = @Storage("CodeGPT_YouSettings.xml"))
|
||||
|
|
@ -33,8 +31,6 @@ public class YouSettings implements PersistentStateComponent<YouSettingsState> {
|
|||
}
|
||||
|
||||
public boolean isModified(YouSettingsForm form) {
|
||||
var password = YouCredentialManager.getInstance().getCredential();
|
||||
return !form.getCurrentState().equals(state)
|
||||
|| (!form.getEmail().isEmpty() && !StringUtils.equals(form.getPassword(), password));
|
||||
return !form.getCurrentState().equals(state);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.standard;
|
||||
package ee.carlrobert.codegpt.toolwindow.chat.ui.textarea;
|
||||
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.CUSTOM_OPENAI;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.OPENAI;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
|
|
@ -15,6 +17,7 @@ import ee.carlrobert.codegpt.conversations.ConversationsState;
|
|||
import ee.carlrobert.codegpt.settings.GeneralSettings;
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettingsState;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.service.custom.CustomServiceSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettingsState;
|
||||
|
|
@ -56,22 +59,19 @@ public class ModelComboBoxAction extends ComboBoxAction {
|
|||
var presentation = ((ComboBoxButton) button).getPresentation();
|
||||
var actionGroup = new DefaultActionGroup();
|
||||
actionGroup.addSeparator("OpenAI");
|
||||
var settings = OpenAISettings.getCurrentState();
|
||||
if (settings.getCustomModel().isEmpty()) {
|
||||
List.of(
|
||||
OpenAIChatCompletionModel.GPT_4_0125_128k,
|
||||
OpenAIChatCompletionModel.GPT_3_5_0125_16k,
|
||||
OpenAIChatCompletionModel.GPT_4_32k,
|
||||
OpenAIChatCompletionModel.GPT_4,
|
||||
OpenAIChatCompletionModel.GPT_3_5)
|
||||
.forEach(model -> actionGroup.add(createOpenAIModelAction(model, presentation)));
|
||||
} else {
|
||||
actionGroup.add(createModelAction(
|
||||
ServiceType.OPENAI,
|
||||
settings.getCustomModel(),
|
||||
Icons.OpenAI,
|
||||
presentation));
|
||||
}
|
||||
List.of(
|
||||
OpenAIChatCompletionModel.GPT_4_0125_128k,
|
||||
OpenAIChatCompletionModel.GPT_3_5_0125_16k,
|
||||
OpenAIChatCompletionModel.GPT_4_32k,
|
||||
OpenAIChatCompletionModel.GPT_4,
|
||||
OpenAIChatCompletionModel.GPT_3_5)
|
||||
.forEach(model -> actionGroup.add(createOpenAIModelAction(model, presentation)));
|
||||
actionGroup.addSeparator("Custom OpenAI Service");
|
||||
actionGroup.add(createModelAction(
|
||||
CUSTOM_OPENAI,
|
||||
CustomServiceSettings.getCurrentState().getTemplate().getName(),
|
||||
Icons.OpenAI,
|
||||
presentation));
|
||||
actionGroup.addSeparator();
|
||||
actionGroup.add(
|
||||
createModelAction(ServiceType.AZURE, "Azure OpenAI", Icons.Azure, presentation));
|
||||
|
|
@ -96,7 +96,14 @@ public class ModelComboBoxAction extends ComboBoxAction {
|
|||
switch (selectedService) {
|
||||
case OPENAI:
|
||||
templatePresentation.setIcon(Icons.OpenAI);
|
||||
templatePresentation.setText(getOpenAiPresentationText());
|
||||
templatePresentation.setText(
|
||||
OpenAIChatCompletionModel.findByCode(openAISettings.getModel()).getDescription());
|
||||
break;
|
||||
case CUSTOM_OPENAI:
|
||||
templatePresentation.setIcon(Icons.OpenAI);
|
||||
templatePresentation.setText(CustomServiceSettings.getCurrentState()
|
||||
.getTemplate()
|
||||
.getName());
|
||||
break;
|
||||
case AZURE:
|
||||
templatePresentation.setIcon(Icons.Azure);
|
||||
|
|
@ -114,14 +121,6 @@ public class ModelComboBoxAction extends ComboBoxAction {
|
|||
}
|
||||
}
|
||||
|
||||
private String getOpenAiPresentationText() {
|
||||
var settings = OpenAISettings.getCurrentState();
|
||||
if (settings.getCustomModel().isEmpty()) {
|
||||
return OpenAIChatCompletionModel.findByCode(openAISettings.getModel()).getDescription();
|
||||
}
|
||||
return settings.getCustomModel();
|
||||
}
|
||||
|
||||
private String getLlamaCppPresentationText() {
|
||||
var llamaSettingState = LlamaSettings.getCurrentState();
|
||||
if (!llamaSettingState.isRunLocalServer()) {
|
||||
|
|
@ -178,7 +177,7 @@ public class ModelComboBoxAction extends ComboBoxAction {
|
|||
private AnAction createOpenAIModelAction(
|
||||
OpenAIChatCompletionModel model,
|
||||
Presentation comboBoxPresentation) {
|
||||
createModelAction(ServiceType.OPENAI, model.getDescription(), Icons.OpenAI,
|
||||
createModelAction(OPENAI, model.getDescription(), Icons.OpenAI,
|
||||
comboBoxPresentation);
|
||||
return new DumbAwareAction(model.getDescription(), "", Icons.OpenAI) {
|
||||
@Override
|
||||
|
|
@ -191,7 +190,7 @@ public class ModelComboBoxAction extends ComboBoxAction {
|
|||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
openAISettings.setModel(model.getCode());
|
||||
handleProviderChange(
|
||||
ServiceType.OPENAI,
|
||||
OPENAI,
|
||||
model.getDescription(),
|
||||
Icons.OpenAI,
|
||||
comboBoxPresentation);
|
||||
|
|
@ -8,7 +8,6 @@ import com.intellij.util.ui.JBUI;
|
|||
import ee.carlrobert.codegpt.completions.you.YouSubscriptionNotifier;
|
||||
import ee.carlrobert.codegpt.completions.you.auth.SignedOutNotifier;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.ModelComboBoxAction;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue