Skip to content

Commit aeee8c9

Browse files
committed
0.1.7 - Asynchronous API
1 parent fd9efa7 commit aeee8c9

File tree

9 files changed

+309
-252
lines changed

9 files changed

+309
-252
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
## [Unreleased]
66

7+
## [0.1.7]
8+
9+
### Added
10+
- All API calls are handled asynchronously - no UI thread blocking!
11+
712
## [0.1.6]
813

914
### Added

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pluginGroup = com.github.simiacryptus
44
pluginName = intellij-aicoder
55
pluginRepositoryUrl = https://github.com/SimiaCryptus/intellij-aicoder
66
# SemVer format -> https://semver.org
7-
pluginVersion = 0.1.6
7+
pluginVersion = 0.1.7
88

99
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
1010
pluginSinceBuild = 203

src/main/java/com/github/simiacryptus/aicoder/EditorMenu.java

Lines changed: 162 additions & 153 deletions
Large diffs are not rendered by default.

src/main/java/com/github/simiacryptus/aicoder/StyleUtil.java

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package com.github.simiacryptus.aicoder;
22

33
import com.github.simiacryptus.aicoder.config.AppSettingsState;
4-
import com.github.simiacryptus.aicoder.openai.ModerationException;
4+
import com.github.simiacryptus.aicoder.openai.CompletionRequest;
5+
import com.github.simiacryptus.aicoder.openai.OpenAI;
56
import com.github.simiacryptus.aicoder.text.IndentedText;
67
import com.github.simiacryptus.aicoder.text.StringTools;
8+
import com.google.common.util.concurrent.ListenableFuture;
79
import com.intellij.openapi.diagnostic.Logger;
810

911
import javax.swing.*;
10-
import java.io.IOException;
1112
import java.util.Arrays;
1213
import java.util.List;
1314
import java.util.Random;
@@ -125,38 +126,32 @@ public static void demoStyle(String style) {
125126
* @param code The code snippet to be described.
126127
*/
127128
public static void demoStyle(String style, ComputerLanguage language, String code) {
128-
String codeDescription = describeTest(style, language, code);
129-
String message = String.format("This code:\n %s\nwas described as:\n %s", code.replace("\n", "\n "), codeDescription.replace("\n", "\n "));
130-
JOptionPane.showMessageDialog(null, message, "Style Demo", JOptionPane.INFORMATION_MESSAGE);
129+
OpenAI.onSuccess(describeTest(style, language, code), description -> {
130+
String message = String.format("This code:\n %s\nwas described as:\n %s", code.replace("\n", "\n "), description.replace("\n", "\n "));
131+
JOptionPane.showMessageDialog(null, message, "Style Demo", JOptionPane.INFORMATION_MESSAGE);
132+
});
131133
}
132134

133135
/**
134136
* Describes some test code in the specified style and language.
135137
*
136-
* @param style The style of the description.
137-
* @param language The language of the test.
138-
* @param code The code.
138+
* @param style The style of the description.
139+
* @param language The language of the test.
140+
* @param code The code.
139141
* @return A description of the test in the specified style and language.
140142
*/
141-
public static String describeTest(String style, ComputerLanguage language, String code) {
143+
public static ListenableFuture<String> describeTest(String style, ComputerLanguage language, String code) {
142144
AppSettingsState settings = AppSettingsState.getInstance();
143-
try {
144-
return StringTools.lineWrapping(settings.createTranslationRequest()
145-
.setInstruction(String.format("Explain this %s in %s (%s)", language.name(), settings.humanLanguage, style))
146-
.setInputText(IndentedText.fromString(code).getTextBlock().trim())
147-
.setInputType(language.name())
148-
.setInputAttribute("type", "code")
149-
.setOutputType(settings.humanLanguage)
150-
.setOutputAttrute("type", "description")
151-
.setOutputAttrute("style", style)
152-
.buildCompletionRequest()
153-
.complete("")
154-
.trim(), 120);
155-
} catch (ModerationException e) {
156-
return e.getMessage();
157-
} catch (IOException e) {
158-
log.error(e);
159-
return e.getMessage();
160-
}
145+
CompletionRequest completionRequest = settings.createTranslationRequest()
146+
.setInstruction(String.format("Explain this %s in %s (%s)", language.name(), settings.humanLanguage, style))
147+
.setInputText(IndentedText.fromString(code).getTextBlock().trim())
148+
.setInputType(language.name())
149+
.setInputAttribute("type", "code")
150+
.setOutputType(settings.humanLanguage)
151+
.setOutputAttrute("type", "description")
152+
.setOutputAttrute("style", style)
153+
.buildCompletionRequest();
154+
ListenableFuture<String> future = completionRequest.complete("");
155+
return OpenAI.map(future, x->StringTools.lineWrapping(x.trim(), 120));
161156
}
162157
}

src/main/java/com/github/simiacryptus/aicoder/TextReplacementAction.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.github.simiacryptus.aicoder;
22

33
import com.github.simiacryptus.aicoder.openai.ModerationException;
4+
import com.github.simiacryptus.aicoder.openai.OpenAI;
5+
import com.google.common.util.concurrent.ListenableFuture;
46
import com.intellij.openapi.actionSystem.AnAction;
57
import com.intellij.openapi.actionSystem.AnActionEvent;
68
import com.intellij.openapi.actionSystem.CommonDataKeys;
@@ -32,7 +34,7 @@ public TextReplacementAction(@Nullable @NlsActions.ActionText String text, @Null
3234
public static @NotNull TextReplacementAction create(@Nullable @NlsActions.ActionText String text, @Nullable @NlsActions.ActionDescription String description, @Nullable Icon icon, @NotNull ActionTextEditorFunction fn) {
3335
return new TextReplacementAction(text, description, icon) {
3436
@Override
35-
protected String edit(@NotNull AnActionEvent e, String previousText) throws IOException, ModerationException {
37+
protected ListenableFuture<String> edit(@NotNull AnActionEvent e, String previousText) throws IOException, ModerationException {
3638
return fn.apply(e, previousText);
3739
}
3840
};
@@ -43,21 +45,23 @@ public void actionPerformed(@NotNull final AnActionEvent e) {
4345
final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
4446
final CaretModel caretModel = editor.getCaretModel();
4547
final Caret primaryCaret = caretModel.getPrimaryCaret();
46-
final String newText;
48+
final ListenableFuture<String> future;
4749
try {
48-
newText = edit(e, primaryCaret.getSelectedText());
49-
WriteCommandAction.runWriteCommandAction(e.getProject(), () -> {
50-
editor.getDocument().replaceString(primaryCaret.getSelectionStart(), primaryCaret.getSelectionEnd(), newText);
50+
future = edit(e, primaryCaret.getSelectedText());
51+
OpenAI.onSuccess(future, newText->{
52+
WriteCommandAction.runWriteCommandAction(e.getProject(), () -> {
53+
editor.getDocument().replaceString(primaryCaret.getSelectionStart(), primaryCaret.getSelectionEnd(), newText);
54+
});
5155
});
5256
} catch (ModerationException | IOException ex) {
5357
EditorMenu.handle(ex);
5458
}
5559
}
5660

57-
protected abstract String edit(@NotNull AnActionEvent e, String previousText) throws IOException, ModerationException;
61+
protected abstract ListenableFuture<String> edit(@NotNull AnActionEvent e, String previousText) throws IOException, ModerationException;
5862

5963
public interface ActionTextEditorFunction {
60-
String apply(AnActionEvent actionEvent, String input) throws IOException, ModerationException;
64+
ListenableFuture<String> apply(AnActionEvent actionEvent, String input) throws IOException, ModerationException;
6165
}
6266

6367
}

src/main/java/com/github/simiacryptus/aicoder/config/AppSettingsComponent.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.github.simiacryptus.aicoder.config;
22

33
import com.fasterxml.jackson.databind.JsonNode;
4-
import com.fasterxml.jackson.databind.node.ObjectNode;
54
import com.github.simiacryptus.aicoder.StyleUtil;
65
import com.github.simiacryptus.aicoder.openai.OpenAI;
76
import com.intellij.openapi.diagnostic.Logger;
@@ -27,19 +26,26 @@ public class AppSettingsComponent extends SimpleSettingsComponent<AppSettingsSta
2726

2827
@NotNull
2928
private static JComponent getModelSelector() {
30-
try {
31-
ObjectNode engines = OpenAI.INSTANCE.getEngines();
32-
JsonNode data = engines.get("data");
33-
String[] items = new String[data.size()];
34-
for (int i = 0; i < data.size(); i++) {
35-
items[i] = data.get(i).get("id").asText();
29+
AppSettingsState settings = AppSettingsState.getInstance();
30+
String apiKey = settings.apiKey;
31+
if (null != apiKey && !apiKey.isEmpty()) {
32+
try {
33+
ComboBox<String> comboBox = new ComboBox<>(new String[]{settings.model});
34+
OpenAI.onSuccess(OpenAI.INSTANCE.getEngines(), engines -> {
35+
JsonNode data = engines.get("data");
36+
String[] items = new String[data.size()];
37+
for (int i = 0; i < data.size(); i++) {
38+
items[i] = data.get(i).get("id").asText();
39+
}
40+
Arrays.sort(items);
41+
Arrays.stream(items).forEach(comboBox::addItem);
42+
});
43+
return comboBox;
44+
} catch (Throwable e) {
45+
log.warn(e);
3646
}
37-
Arrays.sort(items);
38-
return new ComboBox<String>(items);
39-
} catch (Throwable e) {
40-
log.warn(e);
41-
return new JBTextField();
4247
}
48+
return new JBTextField();
4349
}
4450

4551
@Name("Style")
@@ -69,7 +75,7 @@ public void actionPerformed(ActionEvent e) {
6975
@Name("Developer Tools")
7076
public final JBCheckBox devActions = new JBCheckBox();
7177
@Name("API Log Level")
72-
public final ComboBox apiLogLevel = new ComboBox(Arrays.stream(LogLevel.values()).map(x->x.name()).toArray(String[]::new));
78+
public final ComboBox apiLogLevel = new ComboBox(Arrays.stream(LogLevel.values()).map(x -> x.name()).toArray(String[]::new));
7379

7480
// @Name("API Envelope")
7581
// public final ComboBox translationRequestTemplate = new ComboBox(Arrays.stream(TranslationRequestTemplate.values()).map(x->x.name()).toArray(String[]::new));

src/main/java/com/github/simiacryptus/aicoder/openai/CompletionRequest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package com.github.simiacryptus.aicoder.openai;
22

33
import com.github.simiacryptus.aicoder.text.IndentedText;
4+
import com.google.common.util.concurrent.Futures;
5+
import com.google.common.util.concurrent.ListenableFuture;
46
import org.jetbrains.annotations.NotNull;
5-
import org.jetbrains.annotations.Nullable;
67

78
import java.io.IOException;
89
import java.util.ArrayList;
@@ -35,9 +36,8 @@ public CompletionRequest(String prompt, double temperature, int max_tokens, Inte
3536
}
3637

3738
@NotNull
38-
public String complete(String indent) throws IOException, ModerationException {
39-
CompletionResponse response = OpenAI.INSTANCE.complete(this);
40-
return response
39+
public ListenableFuture<String> complete(String indent) {
40+
return OpenAI.map(OpenAI.INSTANCE.complete(this), response -> response
4141
.getFirstChoice()
4242
.map(String::trim)
4343
.map(completion -> stripPrefix(completion, this.prompt.trim()))
@@ -47,7 +47,7 @@ public String complete(String indent) throws IOException, ModerationException {
4747
.map(indentedText -> indentedText.withIndent(indent))
4848
.map(IndentedText::toString)
4949
.map(indentedText -> indent + indentedText)
50-
.orElse("");
50+
.orElse(""));
5151
}
5252

5353
public @NotNull CompletionRequest appendPrompt(String prompt) {

0 commit comments

Comments
 (0)