Support you.com gpt-4 model (#233)

This commit is contained in:
Carl-Robert 2023-10-12 11:18:37 +03:00 committed by GitHub
parent 0343842af9
commit 21fa61d2af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 311 additions and 168 deletions

View file

@ -1,5 +1,7 @@
package ee.carlrobert.codegpt.completions;
import com.intellij.openapi.diagnostic.Logger;
import ee.carlrobert.codegpt.completions.you.YouUserManager;
import ee.carlrobert.codegpt.conversations.Conversation;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.settings.state.AzureSettingsState;
@ -20,6 +22,8 @@ import org.jetbrains.annotations.Nullable;
public class CompletionRequestHandler {
private static final Logger LOG = Logger.getInstance(CompletionRequestHandler.class);
private final StringBuilder messageBuilder = new StringBuilder();
private SwingWorker<Void, String> swingWorker;
private EventSource eventSource;
@ -77,8 +81,21 @@ public class CompletionRequestHandler {
try {
if (settings.isUseYouService()) {
return CompletionClientProvider.getYouClient("", "")
.getChatCompletion(requestProvider.buildYouCompletionRequest(message), eventListener);
var sessionId = "";
var accessToken = "";
var youUserManager = YouUserManager.getInstance();
if (youUserManager.isAuthenticated()) {
var authenticationResponse =
youUserManager.getAuthenticationResponse().getData();
sessionId = authenticationResponse.getSession().getSessionId();
accessToken = authenticationResponse.getSessionJwt();
}
var request = requestProvider.buildYouCompletionRequest(message);
LOG.info("Initiating completion request using model: " +
(request.isUseGPT4Model() ? "GPT-4" : "YouBot"));
return CompletionClientProvider.getYouClient(sessionId, accessToken)
.getChatCompletion(request, eventListener);
}
if (settings.isUseAzureService()) {
@ -130,8 +147,8 @@ public class CompletionRequestHandler {
message,
isRetry,
settings.isUseYouService() ?
getYouCompletionEventListener() :
getCompletionEventListener());
new BaseCompletionEventListener() :
new YouRequestCompletionEventListener());
} catch (TotalUsageExceededException e) {
if (tokensExceededListener != null) {
tokensExceededListener.run();
@ -152,66 +169,41 @@ public class CompletionRequestHandler {
}
}
private CompletionEventListener getCompletionEventListener() {
return new CompletionEventListener() {
@Override
public void onMessage(String message) {
publish(message);
}
class BaseCompletionEventListener implements CompletionEventListener {
@Override
public void onComplete(StringBuilder messageBuilder) {
if (completedListener != null) {
completedListener.accept(messageBuilder.toString());
}
}
@Override
public void onMessage(String message) {
publish(message);
}
@Override
public void onError(ErrorDetails error, Throwable ex) {
try {
if (errorListener != null) {
errorListener.accept(error, ex);
}
} finally {
sendError(error, ex);
}
@Override
public void onComplete(StringBuilder messageBuilder) {
if (completedListener != null) {
completedListener.accept(messageBuilder.toString());
}
};
}
@Override
public void onError(ErrorDetails error, Throwable ex) {
try {
if (errorListener != null) {
errorListener.accept(error, ex);
}
} finally {
sendError(error, ex);
}
}
}
// TODO: Refactor
private YouCompletionEventListener getYouCompletionEventListener() {
return new YouCompletionEventListener() {
@Override
public void onMessage(String message) {
publish(message);
}
class YouRequestCompletionEventListener extends BaseCompletionEventListener
implements YouCompletionEventListener {
@Override
public void onComplete(StringBuilder messageBuilder) {
if (completedListener != null) {
completedListener.accept(messageBuilder.toString());
}
@Override
public void onSerpResults(List<YouSerpResult> results) {
if (serpResultsListener != null) {
serpResultsListener.accept(results);
}
@Override
public void onError(ErrorDetails error, Throwable ex) {
try {
if (errorListener != null) {
errorListener.accept(error, ex);
}
} finally {
sendError(error, ex);
}
}
@Override
public void onSerpResults(List<YouSerpResult> results) {
if (serpResultsListener != null) {
serpResultsListener.accept(results);
}
}
};
}
}
private void sendInfo(SettingsState settings) {

View file

@ -10,6 +10,7 @@ import ee.carlrobert.codegpt.conversations.ConversationsState;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
import ee.carlrobert.codegpt.settings.state.SettingsState;
import ee.carlrobert.codegpt.settings.state.YouSettingsState;
import ee.carlrobert.embedding.EmbeddingsService;
import ee.carlrobert.llm.client.openai.completion.chat.OpenAIChatCompletionModel;
import ee.carlrobert.llm.client.openai.completion.chat.request.OpenAIChatCompletionMessage;
@ -55,6 +56,7 @@ public class CompletionRequestProvider {
public YouCompletionRequest buildYouCompletionRequest(Message message) {
return new YouCompletionRequest.Builder(message.getPrompt())
.setUseGPT4Model(YouSettingsState.getInstance().isUseGPT4Model())
.setChatHistory(conversation.getMessages().stream()
.map(prevMessage -> new YouCompletionRequestMessage(prevMessage.getPrompt(), prevMessage.getResponse()))
.collect(toList()))

View file

@ -19,6 +19,7 @@ import ee.carlrobert.codegpt.settings.state.OpenAISettingsState;
import ee.carlrobert.codegpt.settings.state.SettingsState;
import ee.carlrobert.codegpt.completions.you.YouUserManager;
import ee.carlrobert.codegpt.completions.you.auth.AuthenticationNotifier;
import ee.carlrobert.codegpt.settings.state.YouSettingsState;
import ee.carlrobert.codegpt.util.SwingUtils;
import ee.carlrobert.llm.client.openai.completion.chat.OpenAIChatCompletionModel;
import ee.carlrobert.llm.completion.CompletionModel;
@ -34,7 +35,7 @@ public class ServiceSelectionForm {
private final Disposable parentDisposable;
private static final OpenAIChatCompletionModel[] DEFAULT_OPENAI_MODELS = new OpenAIChatCompletionModel[] {
private static final OpenAIChatCompletionModel[] DEFAULT_OPENAI_MODELS = new OpenAIChatCompletionModel[]{
OpenAIChatCompletionModel.GPT_3_5,
OpenAIChatCompletionModel.GPT_3_5_16k,
OpenAIChatCompletionModel.GPT_4,
@ -88,7 +89,8 @@ public class ServiceSelectionForm {
azureActiveDirectoryTokenField = new JBPasswordField();
azureActiveDirectoryTokenField.setColumns(30);
azureActiveDirectoryTokenField.setText(AzureCredentialsManager.getInstance().getAzureActiveDirectoryToken());
azureActiveDirectoryTokenField.setText(
AzureCredentialsManager.getInstance().getAzureActiveDirectoryToken());
azureActiveDirectoryTokenFieldPanel = UI.PanelFactory.panel(azureActiveDirectoryTokenField)
.withLabel("Bearer token:")
@ -103,26 +105,37 @@ public class ServiceSelectionForm {
azureSettings.isUseAzureActiveDirectoryAuthentication());
useOpenAIServiceRadioButton = new JBRadioButton(
CodeGPTBundle.get("settingsConfigurable.section.service.useOpenAIServiceRadioButtonLabel"), settings.isUseOpenAIService());
CodeGPTBundle.get("settingsConfigurable.section.service.useOpenAIServiceRadioButtonLabel"),
settings.isUseOpenAIService());
useAzureServiceRadioButton = new JBRadioButton(
CodeGPTBundle.get("settingsConfigurable.section.service.useAzureServiceRadioButtonLabel"), settings.isUseAzureService());
CodeGPTBundle.get("settingsConfigurable.section.service.useAzureServiceRadioButtonLabel"),
settings.isUseAzureService());
useYouServiceRadioButton = new JBRadioButton(
CodeGPTBundle.get("settingsConfigurable.section.service.useYouServiceRadioButtonLabel"), settings.isUseYouService());
CodeGPTBundle.get("settingsConfigurable.section.service.useYouServiceRadioButtonLabel"),
settings.isUseYouService());
openAIBaseHostField = new JBTextField(openAISettings.getBaseHost(), 30);
openAIPathField = new JBTextField(openAISettings.getPath(), 30);
openAIOrganizationField = new JBTextField(openAISettings.getOrganization(), 30);
openAICompletionModelComboBox = new ModelComboBox(DEFAULT_OPENAI_MODELS, OpenAIChatCompletionModel.findByCode(openAISettings.getModel()));
openAICompletionModelComboBox = new ModelComboBox(
DEFAULT_OPENAI_MODELS,
OpenAIChatCompletionModel.findByCode(openAISettings.getModel()));
azureBaseHostField = new JBTextField(azureSettings.getBaseHost(), 35);
azurePathField = new JBTextField(azureSettings.getPath(), 35);
azureResourceNameField = new JBTextField(azureSettings.getResourceName(), 35);
azureDeploymentIdField = new JBTextField(azureSettings.getDeploymentId(), 35);
azureApiVersionField = new JBTextField(azureSettings.getApiVersion(), 35);
azureCompletionModelComboBox = new ModelComboBox(DEFAULT_OPENAI_MODELS, OpenAIChatCompletionModel.findByCode(azureSettings.getModel()));
azureCompletionModelComboBox.getEditor().getEditorComponent().setMaximumSize(azureBaseHostField.getPreferredSize());
azureCompletionModelComboBox = new ModelComboBox(
DEFAULT_OPENAI_MODELS,
OpenAIChatCompletionModel.findByCode(azureSettings.getModel()));
azureCompletionModelComboBox.getEditor()
.getEditorComponent()
.setMaximumSize(azureBaseHostField.getPreferredSize());
displayWebSearchResultsCheckBox = new JBCheckBox("Display web search results", settings.isDisplayWebSearchResults());
displayWebSearchResultsCheckBox = new JBCheckBox(
"Display web search results",
YouSettingsState.getInstance().isDisplayWebSearchResults());
displayWebSearchResultsCheckBox.setEnabled(YouUserManager.getInstance().isAuthenticated());
openAIServiceSectionPanel = createOpenAIServiceSectionPanel();
@ -135,7 +148,8 @@ public class ServiceSelectionForm {
ApplicationManager.getApplication()
.getMessageBus()
.connect()
.subscribe(AuthenticationNotifier.AUTHENTICATION_TOPIC, (AuthenticationNotifier) () -> displayWebSearchResultsCheckBox.setEnabled(true));
.subscribe(AuthenticationNotifier.AUTHENTICATION_TOPIC,
(AuthenticationNotifier) () -> displayWebSearchResultsCheckBox.setEnabled(true));
}
public JPanel getForm() {
@ -158,9 +172,11 @@ public class ServiceSelectionForm {
private JPanel createOpenAIServiceSectionPanel() {
var requestConfigurationPanel = UI.PanelFactory.grid()
.add(UI.PanelFactory.panel(openAIOrganizationField)
.withLabel(CodeGPTBundle.get("settingsConfigurable.section.service.openai.organizationField.label"))
.withLabel(CodeGPTBundle.get(
"settingsConfigurable.section.service.openai.organizationField.label"))
.resizeX(false)
.withComment(CodeGPTBundle.get("settingsConfigurable.section.service.openai.organizationField.comment")))
.withComment(CodeGPTBundle.get(
"settingsConfigurable.section.service.openai.organizationField.comment")))
.add(UI.PanelFactory.panel(openAIBaseHostField)
.withLabel("Base host:")
.resizeX(false))
@ -175,7 +191,8 @@ public class ServiceSelectionForm {
var apiKeyFieldPanel = UI.PanelFactory.panel(openAIApiKeyField)
.withLabel(CodeGPTBundle.get("settingsConfigurable.section.integration.apiKeyField.label"))
.resizeX(false)
.withComment(CodeGPTBundle.get("settingsConfigurable.section.integration.apiKeyField.comment"))
.withComment(
CodeGPTBundle.get("settingsConfigurable.section.integration.apiKeyField.comment"))
.withCommentHyperlinkListener(SwingUtils::handleHyperlinkClicked)
.createPanel();
@ -204,17 +221,23 @@ public class ServiceSelectionForm {
var configPanel = withEmptyLeftBorder(UI.PanelFactory.grid()
.add(UI.PanelFactory.panel(azureResourceNameField)
.withLabel(CodeGPTBundle.get("settingsConfigurable.section.service.azure.resourceNameField.label"))
.withLabel(CodeGPTBundle.get(
"settingsConfigurable.section.service.azure.resourceNameField.label"))
.resizeX(false)
.withComment(CodeGPTBundle.get("settingsConfigurable.section.service.azure.resourceNameField.comment")))
.withComment(CodeGPTBundle.get(
"settingsConfigurable.section.service.azure.resourceNameField.comment")))
.add(UI.PanelFactory.panel(azureDeploymentIdField)
.withLabel(CodeGPTBundle.get("settingsConfigurable.section.service.azure.deploymentIdField.label"))
.withLabel(CodeGPTBundle.get(
"settingsConfigurable.section.service.azure.deploymentIdField.label"))
.resizeX(false)
.withComment(CodeGPTBundle.get("settingsConfigurable.section.service.azure.deploymentIdField.comment")))
.withComment(CodeGPTBundle.get(
"settingsConfigurable.section.service.azure.deploymentIdField.comment")))
.add(UI.PanelFactory.panel(azureApiVersionField)
.withLabel(CodeGPTBundle.get("settingsConfigurable.section.service.azure.apiVersionField.label"))
.withLabel(CodeGPTBundle.get(
"settingsConfigurable.section.service.azure.apiVersionField.label"))
.resizeX(false)
.withComment(CodeGPTBundle.get("settingsConfigurable.section.service.azure.apiVersionField.comment")))
.withComment(CodeGPTBundle.get(
"settingsConfigurable.section.service.azure.apiVersionField.comment")))
.add(UI.PanelFactory.panel(azureBaseHostField)
.withLabel("Base host:")
.resizeX(false))
@ -251,7 +274,8 @@ public class ServiceSelectionForm {
openAIServiceSectionPanel.setVisible(settings.isUseOpenAIService());
azureServiceSectionPanel.setVisible(settings.isUseAzureService());
azureApiKeyFieldPanel.setVisible(azureSettings.isUseAzureApiKeyAuthentication());
azureActiveDirectoryTokenFieldPanel.setVisible(azureSettings.isUseAzureActiveDirectoryAuthentication());
azureActiveDirectoryTokenFieldPanel.setVisible(
azureSettings.isUseAzureActiveDirectoryAuthentication());
youServiceSectionPanel.setVisible(settings.isUseYouService());
}
@ -264,7 +288,8 @@ public class ServiceSelectionForm {
registerRadioButtons(
List.of(
Map.entry(useAzureApiKeyAuthenticationRadioButton, azureApiKeyFieldPanel),
Map.entry(useAzureActiveDirectoryAuthenticationRadioButton, azureActiveDirectoryTokenFieldPanel)));
Map.entry(useAzureActiveDirectoryAuthenticationRadioButton,
azureActiveDirectoryTokenFieldPanel)));
}
private void registerRadioButtons(List<Map.Entry<JBRadioButton, JPanel>> entries) {
@ -343,7 +368,9 @@ public class ServiceSelectionForm {
}
public String getOpenAIModel() {
return ((OpenAIChatCompletionModel) (openAICompletionModelComboBox.getModel().getSelectedItem())).getCode();
return ((OpenAIChatCompletionModel) (openAICompletionModelComboBox.getModel()
.getSelectedItem()))
.getCode();
}
public void setAzureActiveDirectoryAuthenticationSelected(boolean selected) {
@ -415,7 +442,9 @@ public class ServiceSelectionForm {
}
public String getAzureModel() {
return ((OpenAIChatCompletionModel) (azureCompletionModelComboBox.getModel().getSelectedItem())).getCode();
return ((OpenAIChatCompletionModel) (azureCompletionModelComboBox.getModel()
.getSelectedItem()))
.getCode();
}
public void setDisplayWebSearchResults(boolean displayWebSearchResults) {

View file

@ -10,6 +10,7 @@ import ee.carlrobert.codegpt.credentials.OpenAICredentialsManager;
import ee.carlrobert.codegpt.settings.state.AzureSettingsState;
import ee.carlrobert.codegpt.settings.state.OpenAISettingsState;
import ee.carlrobert.codegpt.settings.state.SettingsState;
import ee.carlrobert.codegpt.settings.state.YouSettingsState;
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
import ee.carlrobert.codegpt.util.ApplicationUtils;
@ -54,7 +55,8 @@ public class SettingsConfigurable implements Configurable {
isServiceChanged(serviceSelectionForm, settings) ||
openAISettings.isModified(serviceSelectionForm) ||
azureSettings.isModified(serviceSelectionForm) ||
serviceSelectionForm.isDisplayWebSearchResults() != settings.isDisplayWebSearchResults();
serviceSelectionForm.isDisplayWebSearchResults() !=
YouSettingsState.getInstance().isDisplayWebSearchResults();
}
@Override
@ -76,7 +78,8 @@ public class SettingsConfigurable implements Configurable {
settings.setUseOpenAIService(serviceSelectionForm.isOpenAIServiceSelected());
settings.setUseAzureService(serviceSelectionForm.isAzureServiceSelected());
settings.setUseYouService(serviceSelectionForm.isYouServiceSelected());
settings.setDisplayWebSearchResults(serviceSelectionForm.isDisplayWebSearchResults());
YouSettingsState.getInstance()
.setDisplayWebSearchResults(serviceSelectionForm.isDisplayWebSearchResults());
openAISettings.apply(serviceSelectionForm);
azureSettings.apply(serviceSelectionForm);
@ -108,7 +111,8 @@ public class SettingsConfigurable implements Configurable {
openAISettings.reset(serviceSelectionForm);
azureSettings.reset(serviceSelectionForm);
serviceSelectionForm.setDisplayWebSearchResults(settings.isDisplayWebSearchResults());
serviceSelectionForm.setDisplayWebSearchResults(
YouSettingsState.getInstance().isDisplayWebSearchResults());
}
@Override

View file

@ -9,6 +9,7 @@ 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.ui.components.OnOffButton;
import com.intellij.util.ui.AsyncProcessIcon;
import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.JBFont;
@ -51,7 +52,8 @@ public class YouServiceSelectionPanel extends JPanel {
if (!settings.getEmail().isEmpty()) {
passwordField.setText(YouCredentialsManager.getInstance().getAccountPassword());
}
signInButton = new JButton(CodeGPTBundle.get("settingsConfigurable.section.userAuthentication.signIn.label"));
signInButton = new JButton(
CodeGPTBundle.get("settingsConfigurable.section.userAuthentication.signIn.label"));
signUpTextPane = createSignUpTextPane();
loadingSpinner = new AsyncProcessIcon("sign_in_spinner");
loadingSpinner.setBorder(JBUI.Borders.emptyLeft(8));
@ -63,11 +65,15 @@ public class YouServiceSelectionPanel extends JPanel {
signInButton.addActionListener(e -> {
emailValidator.revalidate();
passwordValidator.revalidate();
if (emailValidator.getValidationInfo() == null && passwordValidator.getValidationInfo() == null) {
if (emailValidator.getValidationInfo() == null
&& passwordValidator.getValidationInfo() == null) {
loadingSpinner.resume();
loadingSpinner.setVisible(true);
YouAuthenticationService.getInstance()
.signInAsync(emailField.getText(), new String(passwordField.getPassword()), new UserAuthenticationHandler());
.signInAsync(
emailField.getText(),
new String(passwordField.getPassword()),
new UserAuthenticationHandler());
}
});
@ -91,14 +97,17 @@ public class YouServiceSelectionPanel extends JPanel {
return new String(passwordField.getPassword());
}
private ComponentValidator createInputValidator(Disposable parentDisposable, JComponent component) {
private ComponentValidator createInputValidator(
Disposable parentDisposable,
JComponent component) {
var validator = new ComponentValidator(parentDisposable)
.withValidator(() -> {
String value;
if (component instanceof JBTextField) {
value = ((JBTextField) component).getText();
if (!isValidEmail(value)) {
return new ValidationInfo("The email you entered is invalid.", component).withOKEnabled();
return new ValidationInfo("The email you entered is invalid.", component)
.withOKEnabled();
}
} else {
value = new String(((JPasswordField) component).getPassword());
@ -124,7 +133,8 @@ public class YouServiceSelectionPanel extends JPanel {
}
private JTextPane createSignUpTextPane() {
var textPane = createTextPane("<html><a href=\"https://you.com/code\">Don't have an account? Sign up</a></html>");
var textPane = createTextPane(
"<html><a href=\"https://you.com/code\">Don't have an account? Sign up</a></html>");
textPane.setBorder(JBUI.Borders.emptyLeft(4));
return textPane;
}
@ -148,7 +158,10 @@ public class YouServiceSelectionPanel extends JPanel {
return panel;
}
private JPanel createUserAuthenticationPanel(JBTextField emailAddressField, JBPasswordField passwordField, @Nullable YouAuthenticationError error) {
private JPanel createUserAuthenticationPanel(
JBTextField emailAddressField,
JBPasswordField passwordField,
@Nullable YouAuthenticationError error) {
var contentPanelBuilder = FormBuilder.createFormBuilder()
.addLabeledComponent("Email address:", emailAddressField)
.addLabeledComponent("Password:", passwordField)
@ -160,12 +173,12 @@ public class YouServiceSelectionPanel extends JPanel {
var invalidCredentialsLabel = new JBLabel(error.getErrorMessage());
invalidCredentialsLabel.setForeground(JBColor.red);
invalidCredentialsLabel.setBorder(JBUI.Borders.emptyLeft(4));
contentPanelBuilder.addComponentToRightColumn(invalidCredentialsLabel);
}
return FormBuilder.createFormBuilder()
.addComponent(new TitledSeparator(CodeGPTBundle.get("settingsConfigurable.section.userAuthentication.title")))
.addComponent(new TitledSeparator(
CodeGPTBundle.get("settingsConfigurable.section.userAuthentication.title")))
.addComponent(JBUI.Panels
.simplePanel(contentPanelBuilder.getPanel())
.withBorder(JBUI.Borders.emptyLeft(16)))
@ -175,7 +188,8 @@ public class YouServiceSelectionPanel extends JPanel {
private JPanel createUserInformationPanel(YouUser user) {
var userManager = YouUserManager.getInstance();
var contentPanelBuilder = FormBuilder.createFormBuilder()
.addLabeledComponent("Email address:", new JBLabel(user.getEmails().get(0).getEmail()).withFont(JBFont.label().asBold()));
.addLabeledComponent("Email address:",
new JBLabel(user.getEmails().get(0).getEmail()).withFont(JBFont.label().asBold()));
var signOutButton = new JButton("Sign Out");
signOutButton.addActionListener(e -> {
@ -184,7 +198,8 @@ public class YouServiceSelectionPanel extends JPanel {
});
return FormBuilder.createFormBuilder()
.addComponent(new TitledSeparator(CodeGPTBundle.get("settingsConfigurable.section.userInformation.title")))
.addComponent(new TitledSeparator(
CodeGPTBundle.get("settingsConfigurable.section.userInformation.title")))
.addVerticalGap(8)
.addComponent(JBUI.Panels
.simplePanel(contentPanelBuilder.addVerticalGap(4)
@ -209,13 +224,18 @@ public class YouServiceSelectionPanel extends JPanel {
@Override
public void handleGenericError() {
SwingUtilities.invokeLater(() -> refreshView(
createUserAuthenticationPanel(emailField, passwordField, new YouAuthenticationError("unknown", "Something went wrong."))));
SwingUtilities.invokeLater(() -> refreshView(createUserAuthenticationPanel(
emailField,
passwordField,
new YouAuthenticationError("unknown", "Something went wrong."))));
}
@Override
public void handleError(YouAuthenticationError error) {
SwingUtilities.invokeLater(() -> refreshView(createUserAuthenticationPanel(emailField, passwordField, error)));
SwingUtilities.invokeLater(() -> refreshView(createUserAuthenticationPanel(
emailField,
passwordField,
error)));
}
}

View file

@ -17,7 +17,6 @@ public class SettingsState implements PersistentStateComponent<SettingsState> {
private boolean useOpenAIService = true;
private boolean useAzureService;
private boolean useYouService;
private boolean displayWebSearchResults = true;
public SettingsState() {
}
@ -104,12 +103,4 @@ public class SettingsState implements PersistentStateComponent<SettingsState> {
public void setUseYouService(boolean useYouService) {
this.useYouService = useYouService;
}
public boolean isDisplayWebSearchResults() {
return displayWebSearchResults;
}
public void setDisplayWebSearchResults(boolean displayWebSearchResults) {
this.displayWebSearchResults = displayWebSearchResults;
}
}

View file

@ -0,0 +1,45 @@
package ee.carlrobert.codegpt.settings.state;
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 org.jetbrains.annotations.NotNull;
@State(name = "CodeGPT_YouSettings", storages = @Storage("CodeGPT_YouSettings.xml"))
public class YouSettingsState implements PersistentStateComponent<YouSettingsState> {
private boolean displayWebSearchResults = true;
private boolean useGPT4Model;
public static YouSettingsState getInstance() {
return ApplicationManager.getApplication().getService(YouSettingsState.class);
}
@Override
public YouSettingsState getState() {
return this;
}
@Override
public void loadState(@NotNull YouSettingsState state) {
XmlSerializerUtil.copyBean(state, this);
}
public boolean isDisplayWebSearchResults() {
return displayWebSearchResults;
}
public void setDisplayWebSearchResults(boolean displayWebSearchResults) {
this.displayWebSearchResults = displayWebSearchResults;
}
public boolean isUseGPT4Model() {
return useGPT4Model;
}
public void setUseGPT4Model(boolean useGPT4Model) {
this.useGPT4Model = useGPT4Model;
}
}

View file

@ -5,12 +5,15 @@ import static ee.carlrobert.codegpt.util.ThemeUtils.getPanelBackgroundColor;
import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
import com.intellij.ide.HelpTooltip;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.OnOffButton;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.JBUI.Borders;
import ee.carlrobert.codegpt.actions.ActionType;
import ee.carlrobert.codegpt.completions.CompletionRequestHandler;
import ee.carlrobert.codegpt.completions.you.YouSerpResult;
@ -22,6 +25,7 @@ import ee.carlrobert.codegpt.credentials.OpenAICredentialsManager;
import ee.carlrobert.codegpt.settings.state.AzureSettingsState;
import ee.carlrobert.codegpt.settings.state.OpenAISettingsState;
import ee.carlrobert.codegpt.settings.state.SettingsState;
import ee.carlrobert.codegpt.settings.state.YouSettingsState;
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
import ee.carlrobert.codegpt.toolwindow.ModelIconLabel;
import ee.carlrobert.codegpt.toolwindow.chat.components.ChatMessageResponseBody;
@ -29,10 +33,9 @@ import ee.carlrobert.codegpt.toolwindow.chat.components.ResponsePanel;
import ee.carlrobert.codegpt.toolwindow.chat.components.SmartScroller;
import ee.carlrobert.codegpt.toolwindow.chat.components.UserMessagePanel;
import ee.carlrobert.codegpt.toolwindow.chat.components.UserPromptTextArea;
import ee.carlrobert.codegpt.completions.you.YouUserManager;
import ee.carlrobert.codegpt.util.EditorUtils;
import ee.carlrobert.codegpt.util.file.FileUtils;
import ee.carlrobert.codegpt.util.OverlayUtils;
import ee.carlrobert.codegpt.util.file.FileUtils;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@ -131,10 +134,7 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
public void dispose() {
}
private boolean isCredentialSet() {
if (SettingsState.getInstance().isUseYouService()) {
return YouUserManager.getInstance().isAuthenticated();
}
private boolean isRequestAllowed() {
if (SettingsState.getInstance().isUseAzureService()) {
return AzureCredentialsManager.getInstance().isCredentialSet();
}
@ -148,7 +148,7 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
boolean isRetry) {
ChatMessageResponseBody responseContainer = (ChatMessageResponseBody) responsePanel.getContent();
if (!isCredentialSet()) {
if (!isRequestAllowed()) {
responseContainer.displayMissingCredential();
return;
}
@ -170,7 +170,7 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
var serpResults = serpResultsMapping.get(message.getId());
var containsResults = serpResults != null && !serpResults.isEmpty();
if (SettingsState.getInstance().isDisplayWebSearchResults()) {
if (YouSettingsState.getInstance().isDisplayWebSearchResults()) {
if (containsResults) {
responseContainer.displaySerpResults(serpResults);
}
@ -332,9 +332,10 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
gbc.gridy = 1;
var model = getModel();
var modelIconWrapper = JBUI.Panels.simplePanel(
new ModelIconLabel(getClientCode(), model)).withBorder(JBUI.Borders.empty(0, 0, 8, 4));
modelIconWrapper.setBackground(getPanelBackgroundColor());
var modelIconWrapper = JBUI.Panels
.simplePanel(new ModelIconLabel(getClientCode(), model))
.withBorder(Borders.emptyRight(4))
.withBackground(getPanelBackgroundColor());
var wrapper = new JPanel(new BorderLayout());
wrapper.setBorder(JBUI.Borders.compound(
@ -343,13 +344,46 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
wrapper.setBackground(getPanelBackgroundColor());
wrapper.add(userPromptTextArea, BorderLayout.SOUTH);
if (model != null) {
wrapper.add(modelIconWrapper, BorderLayout.LINE_END);
var header = new JPanel(new BorderLayout());
header.setBackground(getPanelBackgroundColor());
header.setBorder(JBUI.Borders.emptyBottom(8));
if ("YouCode".equals(model)) {
var gpt4ToggleButton = new OnOffButton();
var useGPT4Model = YouSettingsState.getInstance().isUseGPT4Model();
gpt4ToggleButton.setSelected(useGPT4Model);
gpt4ToggleButton.setOnText("GPT-4");
gpt4ToggleButton.setOffText("GPT-4");
gpt4ToggleButton.addActionListener(
actionEvent -> {
project.getMessageBus()
.syncPublisher(YouModelChangeNotifier.YOU_MODEL_CHANGE_NOTIFIER_TOPIC)
.modelChanged(gpt4ToggleButton.isSelected());
YouSettingsState.getInstance().setUseGPT4Model(gpt4ToggleButton.isSelected());
installHelpTooltip(gpt4ToggleButton.isSelected(), gpt4ToggleButton);
});
project.getMessageBus()
.connect()
.subscribe(
YouModelChangeNotifier.YOU_MODEL_CHANGE_NOTIFIER_TOPIC,
(YouModelChangeNotifier) gpt4ToggleButton::setSelected);
installHelpTooltip(useGPT4Model, gpt4ToggleButton);
header.add(gpt4ToggleButton, BorderLayout.LINE_START);
}
header.add(modelIconWrapper, BorderLayout.LINE_END);
wrapper.add(header);
}
rootPanel.add(wrapper, gbc);
userPromptTextArea.requestFocusInWindow();
userPromptTextArea.requestFocus();
}
private void installHelpTooltip(boolean selected, JComponent component) {
new HelpTooltip()
.setDescription(selected ? "Turn off for faster responses" : "Turn on for complex queries")
.installOn(component);
}
private String getClientCode() {
var settings = SettingsState.getInstance();
if (settings.isUseOpenAIService()) {

View file

@ -21,5 +21,6 @@ public interface ChatToolWindowTabPanel extends Disposable {
void startNewConversation(Message message);
void sendMessage(Message message);
void requestFocusForTextArea();
}

View file

@ -0,0 +1,11 @@
package ee.carlrobert.codegpt.toolwindow.chat;
import com.intellij.util.messages.Topic;
public interface YouModelChangeNotifier {
Topic<YouModelChangeNotifier> YOU_MODEL_CHANGE_NOTIFIER_TOPIC =
Topic.create("youModelChangeTopic", YouModelChangeNotifier.class);
void modelChanged(boolean selected);
}

View file

@ -102,9 +102,7 @@ public class ChatMessageResponseBody extends JPanel {
}
public void displayMissingCredential() {
var message = SettingsState.getInstance().isUseYouService() ?
"Please <a href=\"#\">log in</a> to access the chat feature." :
"API key not provided. Open <a href=\"#\">Settings</a> to set one.";
var message = "API key not provided. Open <a href=\"#\">Settings</a> to set one.";
currentlyProcessedTextPane.setText(
format("<html><p style=\"margin-top: 4px; margin-bottom: 8px;\">%s</p></html>", message));
currentlyProcessedTextPane.addHyperlinkListener(e -> {

View file

@ -1,24 +1,19 @@
package ee.carlrobert.codegpt.toolwindow.chat.editor;
import static ee.carlrobert.codegpt.util.file.FileUtils.findFileNameExtensionMapping;
import static java.lang.String.format;
import static ee.carlrobert.codegpt.util.file.FileUtils.findLanguageExtensionMapping;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.EditorKind;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.impl.ContextMenuPopupHandler;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.JBUI;
@ -32,43 +27,26 @@ import ee.carlrobert.codegpt.toolwindow.chat.editor.actions.ReplaceSelectionActi
import ee.carlrobert.codegpt.util.EditorUtils;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.swing.Box;
import javax.swing.JPanel;
public class ResponseEditor extends JPanel implements Disposable {
private final Editor editor;
private final String fileName;
private final String fileExtension;
private final String language;
private final String extension;
public ResponseEditor(
Project project,
String code,
String language,
String markdownLanguage,
Disposable disposableParent) {
super(new BorderLayout());
var fileNameExtensionMapping = findFileNameExtensionMapping(language);
this.fileName = fileNameExtensionMapping.getKey();
this.fileExtension = fileNameExtensionMapping.getValue();
var timestamp = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
var fileName = "temp_" + timestamp + fileExtension;
var lightVirtualFile = new LightVirtualFile(
format("%s/%s", PathManager.getTempPath(), fileName), code);
var document = FileDocumentManager.getInstance().getDocument(lightVirtualFile);
if (document == null) {
document = EditorFactory.getInstance().createDocument(code);
}
EditorUtils.disableHighlighting(project, document);
editor = EditorFactory.getInstance().createEditor(
document,
project,
lightVirtualFile,
true,
EditorKind.UNTYPED);
var extensionMapping = findLanguageExtensionMapping(markdownLanguage);
language = extensionMapping.getKey();
extension = extensionMapping.getValue();
editor = EditorUtils.createEditor(project, extension, code);
DefaultActionGroup group = new DefaultActionGroup();
group.add(new ReplaceCodeInMainEditorAction());
@ -85,12 +63,14 @@ public class ResponseEditor extends JPanel implements Disposable {
editorEx.installPopupHandler(new ContextMenuPopupHandler.Simple(group));
editorEx.setColorsScheme(EditorColorsManager.getInstance().getSchemeForCurrentUITheme());
var settings = editor.getSettings();
var settings = editorEx.getSettings();
settings.setAdditionalColumnsCount(0);
settings.setAdditionalLinesCount(0);
settings.setAdditionalPageAtBottom(false);
settings.setVirtualSpace(false);
settings.setUseSoftWraps(false);
settings.setLineMarkerAreaShown(true);
settings.setGutterIconsShown(true);
add(createHeaderComponent(), BorderLayout.NORTH);
add(editor.getComponent(), BorderLayout.SOUTH);
@ -112,7 +92,7 @@ public class ResponseEditor extends JPanel implements Disposable {
headerComponent.setBorder(JBUI.Borders.compound(
JBUI.Borders.customLine(JBColor.border(), 1, 1, 1, 1),
JBUI.Borders.empty(8)));
headerComponent.add(new JBLabel(fileName), BorderLayout.LINE_START);
headerComponent.add(new JBLabel(language), BorderLayout.LINE_START);
headerComponent.add(createHeaderActions(), BorderLayout.LINE_END);
return headerComponent;
}
@ -123,7 +103,7 @@ public class ResponseEditor extends JPanel implements Disposable {
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(new IconActionButton(new EditAction(editor)));
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(new IconActionButton(new NewFileAction(editor, fileExtension)));
wrapper.add(new IconActionButton(new NewFileAction(editor, extension)));
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(new IconActionButton(new CopyAction(editor)));
wrapper.add(Box.createHorizontalStrut(8));

View file

@ -7,6 +7,7 @@ import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.conversations.Conversation;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.settings.state.SettingsState;
import ee.carlrobert.codegpt.settings.state.YouSettingsState;
import ee.carlrobert.codegpt.toolwindow.chat.BaseChatToolWindowTabPanel;
import ee.carlrobert.codegpt.toolwindow.chat.components.ChatMessageResponseBody;
import ee.carlrobert.codegpt.toolwindow.chat.components.ResponsePanel;
@ -24,7 +25,8 @@ public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
this(project, null);
}
public StandardChatToolWindowTabPanel(@NotNull Project project, @Nullable Conversation conversation) {
public StandardChatToolWindowTabPanel(@NotNull Project project,
@Nullable Conversation conversation) {
super(project, false);
if (conversation == null) {
displayLandingView();
@ -39,12 +41,14 @@ public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
var editor = EditorUtils.getSelectedEditor(project);
if (editor == null || !editor.getSelectionModel().hasSelection()) {
OverlayUtils.showWarningBalloon(
editor == null ? "Unable to locate a selected editor" : "Please select a target code before proceeding",
editor == null ? "Unable to locate a selected editor"
: "Please select a target code before proceeding",
locationOnScreen);
return;
}
var fileExtension = FileUtils.getFileExtension(((EditorImpl) editor).getVirtualFile().getName());
var fileExtension = FileUtils.getFileExtension(
((EditorImpl) editor).getVirtualFile().getName());
var message = new Message(action.getPrompt().replace(
"{{selectedCode}}",
format("\n```%s\n%s\n```", fileExtension, editor.getSelectionModel().getSelectedText())));
@ -66,7 +70,8 @@ public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
.withResponse(message.getResponse());
var serpResults = message.getSerpResults();
if (SettingsState.getInstance().isDisplayWebSearchResults() && serpResults != null && !serpResults.isEmpty()) {
if (YouSettingsState.getInstance().isDisplayWebSearchResults() &&
serpResults != null && !serpResults.isEmpty()) {
messageResponseBody.displaySerpResults(serpResults);
}

View file

@ -1,18 +1,48 @@
package ee.carlrobert.codegpt.util;
import static java.lang.String.format;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.EditorKind;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.testFramework.LightVirtualFile;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class EditorUtils {
public static Editor createEditor(@NotNull Project project, String fileExtension, String code) {
var timestamp = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
var fileName = "temp_" + timestamp + fileExtension;
var lightVirtualFile = new LightVirtualFile(
format("%s/%s", PathManager.getTempPath(), fileName),
code);
var existingDocument = FileDocumentManager.getInstance().getDocument(lightVirtualFile);
var document = existingDocument != null
? existingDocument
: EditorFactory.getInstance().createDocument(code);
disableHighlighting(project, document);
return EditorFactory.getInstance().createEditor(
document,
project,
lightVirtualFile,
false,
EditorKind.MAIN_EDITOR);
}
public static boolean hasSelection(@Nullable Editor editor) {
return editor != null && editor.getSelectionModel().hasSelection();
}

View file

@ -67,17 +67,17 @@ public class FileUtils {
return "";
}
public static Map.Entry<String, String> findFileNameExtensionMapping(String language) {
public static Map.Entry<String, String> findLanguageExtensionMapping(String language) {
var defaultValue = Map.entry("Text", ".txt");
var mapper = new ObjectMapper();
List<FileExtensionLanguageDetails> fileExtensionLanguageMappings;
List<LanguageFileExtensionDetails> languageFileExtensionMappings;
List<FileExtensionLanguageDetails> extensionToLanguageMappings;
List<LanguageFileExtensionDetails> languageToExtensionMappings;
try {
fileExtensionLanguageMappings = mapper.readValue(
extensionToLanguageMappings = mapper.readValue(
getResourceContent("/fileExtensionLanguageMappings.json"), new TypeReference<>() {
});
languageFileExtensionMappings = mapper.readValue(
languageToExtensionMappings = mapper.readValue(
getResourceContent("/languageFileExtensionMappings.json"), new TypeReference<>() {
});
} catch (JsonProcessingException e) {
@ -85,11 +85,11 @@ public class FileUtils {
return defaultValue;
}
return findFirstExtension(languageFileExtensionMappings, language)
.orElseGet(() -> fileExtensionLanguageMappings.stream()
return findFirstExtension(languageToExtensionMappings, language)
.orElseGet(() -> extensionToLanguageMappings.stream()
.filter(it -> it.getExtension().equalsIgnoreCase(language))
.findFirst()
.map(it -> findFirstExtension(languageFileExtensionMappings, it.getValue())
.map(it -> findFirstExtension(languageToExtensionMappings, it.getValue())
.orElse(defaultValue))
.orElse(defaultValue));
}