|
106 | 106 |
|
107 | 107 | import javax.script.ScriptEngine;
|
108 | 108 | import javax.script.ScriptException;
|
109 |
| -import javax.swing.AbstractAction; |
110 |
| -import javax.swing.AbstractButton; |
111 |
| -import javax.swing.BoxLayout; |
112 |
| -import javax.swing.ButtonGroup; |
113 |
| -import javax.swing.JButton; |
114 |
| -import javax.swing.JCheckBoxMenuItem; |
115 |
| -import javax.swing.JDialog; |
116 |
| -import javax.swing.JFrame; |
117 |
| -import javax.swing.JLabel; |
118 |
| -import javax.swing.JMenu; |
119 |
| -import javax.swing.JMenuBar; |
120 |
| -import javax.swing.JMenuItem; |
121 |
| -import javax.swing.JOptionPane; |
122 |
| -import javax.swing.JPanel; |
123 |
| -import javax.swing.JPopupMenu; |
124 |
| -import javax.swing.JRadioButtonMenuItem; |
125 |
| -import javax.swing.JScrollPane; |
126 |
| -import javax.swing.JSplitPane; |
127 |
| -import javax.swing.JTabbedPane; |
128 |
| -import javax.swing.JTextArea; |
129 |
| -import javax.swing.JTextField; |
130 |
| -import javax.swing.JTextPane; |
131 |
| -import javax.swing.JTree; |
132 |
| -import javax.swing.KeyStroke; |
133 |
| -import javax.swing.SwingUtilities; |
134 |
| -import javax.swing.UIManager; |
| 109 | +import javax.swing.*; |
| 110 | +import javax.swing.border.BevelBorder; |
135 | 111 | import javax.swing.event.ChangeEvent;
|
136 | 112 | import javax.swing.event.ChangeListener;
|
137 | 113 | import javax.swing.event.DocumentEvent;
|
|
142 | 118 | import javax.swing.text.Position;
|
143 | 119 | import javax.swing.tree.TreePath;
|
144 | 120 |
|
| 121 | +import com.theokanning.openai.completion.chat.ChatCompletionRequest; |
| 122 | +import com.theokanning.openai.completion.chat.ChatMessage; |
| 123 | +import com.theokanning.openai.completion.chat.ChatMessageRole; |
| 124 | +import com.theokanning.openai.service.OpenAiService; |
145 | 125 | import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
|
146 | 126 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
147 | 127 | import org.fife.ui.rsyntaxtextarea.Theme;
|
|
162 | 142 | import org.scijava.log.LogService;
|
163 | 143 | import org.scijava.module.ModuleException;
|
164 | 144 | import org.scijava.module.ModuleService;
|
| 145 | +import org.scijava.options.OptionsService; |
165 | 146 | import org.scijava.platform.PlatformService;
|
166 | 147 | import org.scijava.plugin.Parameter;
|
167 | 148 | import org.scijava.plugin.PluginInfo;
|
@@ -238,7 +219,7 @@ public class TextEditor extends JFrame implements ActionListener,
|
238 | 219 | gotoLine, makeJar, makeJarWithSource, removeUnusedImports, sortImports,
|
239 | 220 | removeTrailingWhitespace, findNext, findPrevious, openHelp, addImport,
|
240 | 221 | nextError, previousError, openHelpWithoutFrames, nextTab,
|
241 |
| - previousTab, runSelection, extractSourceJar, |
| 222 | + previousTab, runSelection, extractSourceJar, askChatGPTtoGenerateCode, |
242 | 223 | openSourceForClass,
|
243 | 224 | //openSourceForMenuItem, // this never had an actionListener!??
|
244 | 225 | openMacroFunctions, decreaseFontSize, increaseFontSize, chooseFontSize,
|
@@ -296,6 +277,8 @@ public class TextEditor extends JFrame implements ActionListener,
|
296 | 277 | private AppService appService;
|
297 | 278 | @Parameter
|
298 | 279 | private BatchService batchService;
|
| 280 | + @Parameter(required = false) |
| 281 | + private OptionsService optionsService; |
299 | 282 |
|
300 | 283 | private Map<ScriptLanguage, JRadioButtonMenuItem> languageMenuItems;
|
301 | 284 | private JRadioButtonMenuItem noneLanguageItem;
|
@@ -534,6 +517,11 @@ public TextEditor(final Context context) {
|
534 | 517 | openSourceForClass.setMnemonic(KeyEvent.VK_J);
|
535 | 518 | //openSourceForMenuItem = addToMenu(toolsMenu, "Open Java File for Menu Item...", 0, 0);
|
536 | 519 | //openSourceForMenuItem.setMnemonic(KeyEvent.VK_M);
|
| 520 | + |
| 521 | + GuiUtils.addMenubarSeparator(toolsMenu, "chatGPT"); |
| 522 | + askChatGPTtoGenerateCode = addToMenu(toolsMenu, "Ask chatGPT...", 0, 0); |
| 523 | + |
| 524 | + |
537 | 525 | addScritpEditorMacroCommands(toolsMenu);
|
538 | 526 | mbar.add(toolsMenu);
|
539 | 527 |
|
@@ -1638,6 +1626,7 @@ else if (source == chooseTabSize) {
|
1638 | 1626 | }
|
1639 | 1627 | else if (source == openClassOrPackageHelp) openClassOrPackageHelp(null);
|
1640 | 1628 | else if (source == extractSourceJar) extractSourceJar();
|
| 1629 | + else if (source == askChatGPTtoGenerateCode) askChatGPTtoGenerateCode(); |
1641 | 1630 | else if (source == openSourceForClass) {
|
1642 | 1631 | final String className = getSelectedClassNameOrAsk("Class (fully qualified name):", "Which Class?");
|
1643 | 1632 | if (className != null) {
|
@@ -3254,6 +3243,75 @@ public void extractSourceJar() {
|
3254 | 3243 | if (file != null) extractSourceJar(file);
|
3255 | 3244 | }
|
3256 | 3245 |
|
| 3246 | + public void askChatGPTtoGenerateCode() { |
| 3247 | + SwingUtilities.invokeLater(() -> { |
| 3248 | + |
| 3249 | + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); |
| 3250 | + |
| 3251 | + // setup default prompt |
| 3252 | + String prompt = |
| 3253 | + "Write code in " + getCurrentLanguage().getLanguageName() + ".\n" + |
| 3254 | + "Write concise and high quality code for ImageJ/Fiji.\n" + |
| 3255 | + "Put minimal comments explaining what the code does.\n" + |
| 3256 | + "The code should do the following:\n" + |
| 3257 | + getTextArea().getSelectedText(); |
| 3258 | + |
| 3259 | + String answer = askChatGPT(prompt); |
| 3260 | + |
| 3261 | + if (answer.contains("```")) { |
| 3262 | + // clean answer by removing blabla outside the code block |
| 3263 | + answer = answer.replace("```java", "```"); |
| 3264 | + answer = answer.replace("```javascript", "```"); |
| 3265 | + answer = answer.replace("```python", "```"); |
| 3266 | + answer = answer.replace("```jython", "```"); |
| 3267 | + answer = answer.replace("```macro", "```"); |
| 3268 | + answer = answer.replace("```groovy", "```"); |
| 3269 | + |
| 3270 | + String[] temp = answer.split("```"); |
| 3271 | + answer = temp[1]; |
| 3272 | + } |
| 3273 | + |
| 3274 | + //getTextArea().insert(answer, getTextArea().getCaretPosition()); |
| 3275 | + getTextArea().replaceSelection(answer + "\n"); |
| 3276 | + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); |
| 3277 | + }); |
| 3278 | + } |
| 3279 | + |
| 3280 | + private String askChatGPT(String text) { |
| 3281 | + // Modified from: https://github.com/TheoKanning/openai-java/blob/main/example/src/main/java/example/OpenAiApiFunctionsExample.java |
| 3282 | + String token = apiKey(); |
| 3283 | + |
| 3284 | + OpenAiService service = new OpenAiService(token); |
| 3285 | + |
| 3286 | + List<ChatMessage> messages = new ArrayList<>(); |
| 3287 | + ChatMessage userMessage = new ChatMessage(ChatMessageRole.USER.value(), text); |
| 3288 | + messages.add(userMessage); |
| 3289 | + |
| 3290 | + ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest |
| 3291 | + .builder() |
| 3292 | + .model("gpt-3.5-turbo-0613") |
| 3293 | + .messages(messages).build(); |
| 3294 | + |
| 3295 | + ChatMessage responseMessage = service.createChatCompletion(chatCompletionRequest).getChoices().get(0).getMessage(); |
| 3296 | + messages.add(responseMessage); |
| 3297 | + |
| 3298 | + String result = responseMessage.getContent(); |
| 3299 | + System.out.println(result); |
| 3300 | + return result; |
| 3301 | + } |
| 3302 | + |
| 3303 | + private String apiKey() { |
| 3304 | + if (optionsService != null) { |
| 3305 | + final OpenAIOptions openAIOptions = |
| 3306 | + optionsService.getOptions(OpenAIOptions.class); |
| 3307 | + if (openAIOptions != null) { |
| 3308 | + final String key = openAIOptions.getOpenAIKey(); |
| 3309 | + if (key != null && !key.isEmpty()) return key; |
| 3310 | + } |
| 3311 | + } |
| 3312 | + return System.getenv("OPENAI_API_KEY"); |
| 3313 | + } |
| 3314 | + |
3257 | 3315 | public void extractSourceJar(final File file) {
|
3258 | 3316 | try {
|
3259 | 3317 | final FileFunctions functions = new FileFunctions(this);
|
|
0 commit comments