Skip to content

Commit

Permalink
Ask AI from project and packages
Browse files Browse the repository at this point in the history
  • Loading branch information
jShiwaniGupta committed Oct 19, 2024
1 parent e8efda0 commit 892ab6f
Show file tree
Hide file tree
Showing 13 changed files with 495 additions and 172 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@
<artifactId>org-netbeans-modules-projectapi</artifactId>
<version>RELEASE230</version>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-openide-dialogs</artifactId>
<version>RELEASE230</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
92 changes: 62 additions & 30 deletions src/main/java/io/github/jeddict/ai/JeddictChatModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ public class JeddictChatModel {
public JeddictChatModel() {
if (null != preferencesManager.getModel()) {
switch (preferencesManager.getProvider()) {
case GOOGLE -> model = GoogleAiGeminiChatModel.builder()
case GOOGLE ->
model = GoogleAiGeminiChatModel.builder()
.apiKey(preferencesManager.getApiKey())
.modelName(preferencesManager.getModelName())
.build();
case OPEN_AI -> model = OpenAiChatModel.builder()
case OPEN_AI ->
model = OpenAiChatModel.builder()
.apiKey(preferencesManager.getApiKey())
.modelName(preferencesManager.getModelName())
.build();
Expand All @@ -76,23 +78,28 @@ public JeddictChatModel() {
.apiKey(preferencesManager.getApiKey())
.modelName(preferencesManager.getModelName())
.build();
case MISTRAL -> model = MistralAiChatModel.builder()
.apiKey(preferencesManager.getApiKey())
.modelName(preferencesManager.getModelName())
.build();
case ANTHROPIC -> model = AnthropicChatModel.builder()
.apiKey(preferencesManager.getApiKey())
.modelName(preferencesManager.getModelName())
.build();
case OLLAMA -> model = OllamaChatModel.builder()
case MISTRAL ->
model = MistralAiChatModel.builder()
.apiKey(preferencesManager.getApiKey())
.modelName(preferencesManager.getModelName())
.build();
case ANTHROPIC ->
model = AnthropicChatModel.builder()
.apiKey(preferencesManager.getApiKey())
.modelName(preferencesManager.getModelName())
.build();
case OLLAMA ->
model = OllamaChatModel.builder()
.baseUrl(preferencesManager.getProviderLocation())
.modelName(preferencesManager.getModelName())
.build();
case LM_STUDIO -> model = LMStudioChatModel.builder()
case LM_STUDIO ->
model = LMStudioChatModel.builder()
.baseUrl(preferencesManager.getProviderLocation())
.modelName(preferencesManager.getModelName())
.build();
case GPT4ALL -> model = LocalAiChatModel.builder()
case GPT4ALL ->
model = LocalAiChatModel.builder()
.baseUrl(preferencesManager.getProviderLocation())
.modelName(preferencesManager.getModelName())
.build();
Expand All @@ -101,11 +108,11 @@ public JeddictChatModel() {
}

private String generate(String prompt) {
if(model == null) {
JOptionPane.showMessageDialog(null,
"AI assistance model not intitalized.",
"Error in AI Assistance",
JOptionPane.ERROR_MESSAGE);
if (model == null) {
JOptionPane.showMessageDialog(null,
"AI assistance model not intitalized.",
"Error in AI Assistance",
JOptionPane.ERROR_MESSAGE);
}
try {
return model.generate(prompt);
Expand Down Expand Up @@ -460,8 +467,8 @@ public List<Snippet> suggestNextLineCode(String classDatas, String classContent,
+ (preferencesManager.isDescriptionEnabled() ? jsonRequestWithDescription : jsonRequest)
+ "Java Class Content:\n" + classContent;
} else if (path.getLeaf().getKind() == Tree.Kind.MODIFIERS
&& path.getParentPath() != null
&& path.getParentPath().getLeaf().getKind() == Tree.Kind.METHOD) {
&& path.getParentPath() != null
&& path.getParentPath().getLeaf().getKind() == Tree.Kind.METHOD) {
prompt = "You are an API server that suggests Java code modifications for a method. "
+ "At the placeholder location ${SUGGEST_CODE_LIST}, suggest method-level modifiers such as 'public', 'protected', 'private', 'abstract', 'static', 'final', 'synchronized', or relevant method-level annotations. "
+ "Additionally, you may suggest method-specific annotations like '@Override', '@Deprecated', '@Transactional', etc. "
Expand All @@ -485,8 +492,8 @@ public List<Snippet> suggestNextLineCode(String classDatas, String classContent,
+ (preferencesManager.isDescriptionEnabled() ? jsonRequestWithDescription : jsonRequest)
+ "Java Class Content:\n" + classContent;
} else if (path.getLeaf().getKind() == Tree.Kind.PARENTHESIZED
&& path.getParentPath() != null
&& path.getParentPath().getLeaf().getKind() == Tree.Kind.IF) {
&& path.getParentPath() != null
&& path.getParentPath().getLeaf().getKind() == Tree.Kind.IF) {
prompt = "You are an API server that suggests Java code to enhance an if-statement. "
+ "At the placeholder location ${SUGGEST_IF_CONDITIONS}, suggest additional conditional checks or actions within the if-statement. "
+ "Ensure that the suggestions are contextually appropriate for the condition. "
Expand All @@ -509,7 +516,7 @@ public List<Snippet> suggestNextLineCode(String classDatas, String classContent,
List<Snippet> nextLines = parseJsonToSnippets(jsonResponse);
return nextLines;
}

public List<String> suggestJavaComment(String classDatas, String classContent, String lineText) {
String prompt = "You are an API server that suggests appropriate Java comments for a specific context in a given Java class at the placeholder location ${SUGGEST_JAVA_COMMENT}. "
+ "Based on the provided Java class content and the line of comment: \"" + lineText + " ${SUGGEST_JAVA_COMMENT} \", suggest relevant Java comment as appropriate for the context represented by the placeholder ${SUGGEST_JAVA_COMMENT} in the Java Class. "
Expand Down Expand Up @@ -543,8 +550,7 @@ public List<String> suggestJavadocOrComment(String classDatas, String classConte
+ "'imports' should be an array of required Java import statements (if no imports are required, return an empty array). "
+ "'snippet' should contain the suggested code as a text block, which may include multiple lines formatted as a single string using \\n for line breaks. "
+ "Make sure to escape any double quotes within the snippet using a backslash (\\) so that the JSON remains valid. \n\n";



String jsonRequestWithDescription = "Return a JSON array with a few best suggestions without any additional text or explanation. Each element should be an object containing three fields: 'imports', 'snippet', and 'description'. "
+ "'imports' should be an array of required Java import statements (if no imports are required, return an empty array). "
+ "'snippet' should contain the suggested code as a text block, which may include multiple lines formatted as a single string using \\n for line breaks. "
Expand All @@ -567,7 +573,7 @@ public List<Snippet> suggestAnnotations(String classDatas, String classContent,
}

public List<Snippet> parseJsonToSnippets(String jsonResponse) {
if(jsonResponse == null) {
if (jsonResponse == null) {
return Collections.EMPTY_LIST;
}
List<Snippet> snippets = new ArrayList<>();
Expand Down Expand Up @@ -597,7 +603,7 @@ public List<Snippet> parseJsonToSnippets(String jsonResponse) {

// Extract the "snippet" field
String snippet = jsonObject.getString("snippet");
if(jsonObject.has("description")){
if (jsonObject.has("description")) {
String descripion = jsonObject.getString("description");
Snippet snippetObj = new Snippet(snippet, descripion, importsList);
snippets.add(snippetObj);
Expand Down Expand Up @@ -638,7 +644,7 @@ private List<String> parseJsonToList(String json) {

private List<String> parseJsonToListWithSplit(String json) {
List<String> variableNames = new ArrayList<>();
if(json == null || json.isEmpty()){
if (json == null || json.isEmpty()) {
return variableNames;
}

Expand Down Expand Up @@ -715,20 +721,39 @@ public String enhanceExpressionStatement(String classContent, String parentConte
return enhanced;
}

public String generateHtmlDescriptionForProject(String projectContent, String query) {
String prompt = "You are an API server that provides answer to query of following project in HTML. "
+ "Do not include additional text or explanations outside of the HTML content.\n\n"
+ "Do not include text in <code> block.\n\n"
+ "If Full Java Class is in response then wrap it in <pre><code type=\"full\" class=\"java\"></pre>. "
+ "If partial snippet of Java Class are in response then wrap it in <pre><code type=\"snippet\" class=\"java\"></pre>. "
+ "Projects Content:\n" + projectContent + "\n\n"
+ "Query:\n" + query;

// Generate the HTML description
String answer = generate(prompt);
System.out.println(answer);
return answer;
}

public String generateHtmlDescriptionForClass(String classContent) {
String prompt = "You are an API server that provides description of following class in HTML. "
+ "Do not include additional text or explanations outside of the HTML content.\n\n"
+ "If Full Java Class is in response then wrap it in <pre><code type=\"full\" class=\"java\"></pre>. "
+ "If partial snippet of Java Class are in response then wrap it in <pre><code type=\"snippet\" class=\"java\"></pre>. "
+ "Java Class Content:\n" + classContent;

// Generate the HTML description
String answer = generate(prompt);
System.out.println(answer);
return answer;
}

public String generateHtmlDescriptionForMethod(String methodContent) {
String prompt = "You are an API server that provides description of following Method in HTML. "
+ "Do not include additional text or explanations outside of the HTML content.\n\n"
+ "If Full Java Class is in response then wrap it in <pre><code type=\"full\" class=\"java\"></pre>. "
+ "If partial snippet of Java Class are in response then wrap it in <pre><code type=\"snippet\" class=\"java\"></pre>. "
+ "Java Method Content:\n" + methodContent;

// Generate the HTML description
Expand All @@ -737,12 +762,19 @@ public String generateHtmlDescriptionForMethod(String methodContent) {
return answer;
}

public String generateHtmlDescription(String classContent, String methodContent, String previousChatResponse, String userQuery) {
public String generateHtmlDescription(
String projectContent, String classContent, String methodContent,
String previousChatResponse, String userQuery) {
String prompt;
String promptExtend;
if (methodContent != null) {
promptExtend = "Method Content:\n" + methodContent + "\n\n"
+ "Do not return complete Java Class, return only Method and wrap it in <code type=\"full\" class=\"java\">. \n";
} else if (projectContent != null) {
promptExtend = "Project Full Content:\n" + classContent + "\n\n"
+ "If Full Java Class is in response then wrap it in <code type=\"full\" class=\"java\">. "
+ "If partial snippet of Java Class are in response then wrap it in <code type=\"snippet\" class=\"java\">. ";

} else {
promptExtend = "Orignal Java Class Content:\n" + classContent + "\n\n"
+ "If Full Java Class is in response then wrap it in <code type=\"full\" class=\"java\">. "
Expand Down
84 changes: 84 additions & 0 deletions src/main/java/io/github/jeddict/ai/actions/AskAIPackageAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.github.jeddict.ai.actions;

import io.github.jeddict.ai.hints.LearnFix;
import io.github.jeddict.ai.settings.PreferencesManager;
import static io.github.jeddict.ai.util.UIUtil.askQuery;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.awt.DynamicMenuContent;
import org.openide.filesystems.FileObject;
import org.openide.util.ContextAwareAction;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;

@ActionID(
category = "Project",
id = "io.github.jeddict.ai.actions.AskAIPackageAction")
@ActionRegistration(
displayName = "#CTL_AskAIPackageAction", lazy = false, asynchronous = true)
@ActionReference(path = "Projects/package/Actions", position = 100)
@Messages({"CTL_AskAIPackageAction=Ask AI"})
public final class AskAIPackageAction extends AbstractAction implements ContextAwareAction {

@Override
public void actionPerformed(ActionEvent ev) {
}

@Override
public Action createContextAwareInstance(Lookup actionContext) {
if (actionContext != null) {
return new AskAIPackageAction.ContextAction(
PreferencesManager.getInstance().isAiAssistantActivated(),
actionContext.lookupAll(FileObject.class)
);
}
return new AskAIPackageAction.ContextAction(false, null);
}

private static final class ContextAction extends AbstractAction {

private final Collection<? extends FileObject> selectedPackages;

private ContextAction(boolean enable, Collection<? extends FileObject> selectedPackages) {
super(Bundle.CTL_AskAIPackageAction());
this.putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true);
this.setEnabled(enable);
this.selectedPackages = selectedPackages;
}

@Override
public void actionPerformed(ActionEvent evt) {
String query = askQuery();
if (query == null) {
return;
}
LearnFix learnFix = new LearnFix(io.github.jeddict.ai.completion.Action.QUERY);
learnFix.askQueryForPackage(selectedPackages, query);
}

}
}
84 changes: 84 additions & 0 deletions src/main/java/io/github/jeddict/ai/actions/AskAIProjectAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.github.jeddict.ai.actions;

import io.github.jeddict.ai.hints.LearnFix;
import io.github.jeddict.ai.settings.PreferencesManager;
import static io.github.jeddict.ai.util.UIUtil.askQuery;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.netbeans.api.project.Project;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.awt.DynamicMenuContent;
import org.openide.util.ContextAwareAction;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;

@ActionID(
category = "Project",
id = "io.github.jeddict.ai.actions.AskAIProjectAction")
@ActionRegistration(
displayName = "#CTL_AskAIProjectAction", lazy = false, asynchronous = true)
@ActionReferences({
@ActionReference(path = "Projects/Actions", position = 100),})
@Messages({"CTL_AskAIProjectAction=Ask AI"})
public final class AskAIProjectAction extends AbstractAction implements ContextAwareAction {

@Override
public void actionPerformed(ActionEvent ev) {
}

@Override
public Action createContextAwareInstance(Lookup actionContext) {
if (actionContext != null) {
return new AskAIProjectAction.ContextAction(
PreferencesManager.getInstance().isAiAssistantActivated(),
actionContext.lookup(Project.class)
);
}
return new AskAIProjectAction.ContextAction(false, null);
}

private static final class ContextAction extends AbstractAction {

private final Project project;

private ContextAction(boolean enable, Project project) {
super(Bundle.CTL_AskAIProjectAction());
this.putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true);
this.setEnabled(enable);
this.project = project;
}

@Override
public void actionPerformed(ActionEvent evt) {
String query = askQuery();
if (query == null) {
return;
}
LearnFix learnFix = new LearnFix(io.github.jeddict.ai.completion.Action.QUERY);
learnFix.askQueryForProject(project, query);
}

}
}
Loading

0 comments on commit 892ab6f

Please sign in to comment.