Skip to content

Commit

Permalink
Merge pull request #28 from jeddict/feature
Browse files Browse the repository at this point in the history
Auto AI Completion support in SQL Editor
  • Loading branch information
jGauravGupta authored Oct 20, 2024
2 parents 1f46089 + 647e87b commit eba4136
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
hs_err_pid*
replay_pid*
/target/
test
15 changes: 15 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@
<id>org.netbeans.modules:org-netbeans-modules-java-editor</id>
<type>impl</type>
</dependency>
<dependency>
<id>org.netbeans.api:org-netbeans-modules-db-core</id>
<type>impl</type>
</dependency>
</moduleDependencies>
<publicPackages>
<publicPackage>io.github.jeddict.ai</publicPackage>
Expand Down Expand Up @@ -411,6 +415,17 @@
<artifactId>org-openide-dialogs</artifactId>
<version>RELEASE230</version>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-modules-db-core</artifactId>
<version>RELEASE230</version>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-modules-db</artifactId>
<version>RELEASE230</version>
</dependency>

</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
38 changes: 35 additions & 3 deletions src/main/java/io/github/jeddict/ai/JeddictChatModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -763,18 +763,18 @@ public String generateHtmlDescriptionForMethod(String methodContent) {
}

public String generateHtmlDescription(
String projectContent, String classContent, String methodContent,
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"
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 Expand Up @@ -830,4 +830,36 @@ public List<Snippet> suggestNextLineCode(String fileContent, String currentLine,
return nextLines;
}

public List<Snippet> suggestSQLQuery(String dbMetadata, String editorContent) {
StringBuilder prompt = new StringBuilder("You are an API server that provides SQL query suggestions based on the provided database schema metadata. ");

if (editorContent == null || editorContent.isEmpty()) {
prompt.append("Analyze the metadata and recommend appropriate SQL queries at the placeholder ${SUGGEST_SQL_QUERY_LIST}. ");
} else {
prompt.append("Based on the following content in the editor: \n")
.append(editorContent)
.append("\nAnalyze the metadata and recommend SQL queries at the placeholder ${SUGGEST_SQL_QUERY_LIST}. ");
}

prompt.append("""
Ensure the SQL queries match the database structure, constraints, and relationships.
Respond with a JSON array containing the best SQL query options.
Each entry should have one field, 'snippet', holding the recommended SQL query block, which may include multiple lines formatted as a single string using \\n for line breaks.
""");

// Include description if enabled
if (preferencesManager.isDescriptionEnabled()) {
prompt.append("""
Additionally, each entry should contain a 'description' field providing a very short explanation of what the query does and why it might be appropriate in this context,
formatted with <b>, <br> tags, and optionally, if required, include any important link with <a href=''> tags.
""");
}

prompt.append("Database Metadata:\n").append(dbMetadata);

String jsonResponse = generate(prompt.toString());
List<Snippet> sqlQueries = parseJsonToSnippets(jsonResponse);
return sqlQueries;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,8 @@
import java.io.OutputStream;
import java.io.PrintWriter;
import org.netbeans.api.editor.completion.Completion;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import static org.netbeans.spi.editor.completion.CompletionProvider.COMPLETION_QUERY_TYPE;
import org.netbeans.modules.db.sql.loader.SQLEditorSupport;

@MimeRegistration(mimeType = "", service = CompletionProvider.class, position = 100)
public class JeddictCompletionProvider implements CompletionProvider {
Expand Down Expand Up @@ -264,14 +263,13 @@ private Set<String> findReferencedClasses(CompilationUnitTree compilationUnit) {

private JeddictItem createItem(Snippet varName, String line, String lineTextBeforeCaret, JavaToken javaToken, Tree.Kind kind, Document doc) throws BadLocationException {
int newcaretOffset = caretOffset;
if(javaToken.getId() == STRING_LITERAL && kind == Tree.Kind.STRING_LITERAL) {
if (javaToken.getId() == STRING_LITERAL && kind == Tree.Kind.STRING_LITERAL) {
lineTextBeforeCaret = doc.getText(javaToken.getOffset(), newcaretOffset - javaToken.getOffset());
if(lineTextBeforeCaret.startsWith("\"")) {
if (lineTextBeforeCaret.startsWith("\"")) {
lineTextBeforeCaret = lineTextBeforeCaret.substring(1);
}
}



String snippetWOSpace = removeAllSpaces(varName.getSnippet());
String tlLine = trimLeadingSpaces(line);
String tlLineTextBeforeCaret = trimLeadingSpaces(lineTextBeforeCaret);
Expand All @@ -281,17 +279,17 @@ private JeddictItem createItem(Snippet varName, String line, String lineTextBefo
String lastWordLine = "";
if (lineTextBeforeCaret != null && !lineTextBeforeCaret.trim().isEmpty()) {
String[] textSegments = lineTextBeforeCaret.trim().split("[^a-zA-Z0-9<]+");
if(textSegments.length > 0) {
if (textSegments.length > 0) {
firstWordLine = textSegments[0];
lastWordLine = textSegments[textSegments.length - 1];
}
}

String firstWordSnippet = "";
if (varName.getSnippet() != null && !varName.getSnippet().trim().isEmpty()) {
String[] textSegments = varName.getSnippet().trim().split("[^a-zA-Z0-9]+");
if(textSegments.length > 0) {
firstWordSnippet = textSegments[0]; // Split by any non-alphanumeric character
String[] textSegments = varName.getSnippet().trim().split("[^a-zA-Z0-9]+");
if (textSegments.length > 0) {
firstWordSnippet = textSegments[0]; // Split by any non-alphanumeric character
}
}

Expand Down Expand Up @@ -335,8 +333,8 @@ protected void query(CompletionResultSet resultSet, Document doc, int caretOffse
this.caretOffset = caretOffset;
String mimeType = (String) doc.getProperty("mimeType");
JavaToken javaToken = isJavaContext(component.getDocument(), caretOffset, true);
if(javaToken != null) {
System.out.println("javaToken " +javaToken.getId());
if (javaToken != null) {
System.out.println("javaToken " + javaToken.getId());
}
if (COMPLETION_QUERY_TYPE == queryType && JAVA_MIME.equals(mimeType)
&& javaToken.isJavaContext()) {
Expand All @@ -355,14 +353,14 @@ protected void query(CompletionResultSet resultSet, Document doc, int caretOffse
String classDataContent = classDatas.stream()
.map(cd -> cd.toString())
.collect(Collectors.joining("\n--------------------\n"));

if (path != null) {
System.out.println("path.getLeaf().getKind() " + path.getLeaf().getKind());
if (path.getParentPath() != null) {
System.out.println("path.getParentPath().getLeaf().getKind() " + path.getParentPath().getLeaf().getKind());
if (path.getParentPath().getParentPath() != null) {
System.out.println("path.getParentPath().getParentPath().getLeaf().getKind() " + path.getParentPath().getParentPath().getLeaf().getKind());
}
System.out.println("path.getParentPath().getParentPath().getLeaf().getKind() " + path.getParentPath().getParentPath().getLeaf().getKind());
}
}
}

Expand All @@ -386,7 +384,7 @@ && trimLeadingSpaces(line).charAt(0) == '@') || kind == Tree.Kind.ANNOTATION) {
String updateddoc = insertPlaceholderAtCaret(doc, caretOffset, "${SUGGEST_CODE_LIST}");
List<Snippet> annotationSuggestions = getJeddictChatModel(fileObject).suggestAnnotations(classDataContent, updateddoc, line);
for (Snippet annotationSuggestion : annotationSuggestions) {
resultSet.addItem(createItem(annotationSuggestion, line, lineTextBeforeCaret,javaToken, kind, doc));
resultSet.addItem(createItem(annotationSuggestion, line, lineTextBeforeCaret, javaToken, kind, doc));
}
} else if (kind == Tree.Kind.MODIFIERS
|| kind == Tree.Kind.IDENTIFIER) {
Expand Down Expand Up @@ -452,7 +450,7 @@ && trimLeadingSpaces(line).charAt(0) == '@') || kind == Tree.Kind.ANNOTATION) {
resultSet.addItem(var);
}
} else {
System.out.println("Skipped : " +kind + " " + path.getLeaf().toString());
System.out.println("Skipped : " + kind + " " + path.getLeaf().toString());
}
} else if (COMPLETION_QUERY_TYPE == queryType && JAVA_MIME.equals(mimeType)) {
String line = getLineText(doc, caretOffset);
Expand Down Expand Up @@ -499,10 +497,20 @@ && trimLeadingSpaces(line).charAt(0) == '@') || kind == Tree.Kind.ANNOTATION) {
String line = getLineText(doc, caretOffset);
String lineTextBeforeCaret = getLineTextBeforeCaret(doc, caretOffset);
FileObject fileObject = getFileObjectFromEditor(doc);
String updateddoc = insertPlaceholderAtCaret(doc, caretOffset, "${SUGGEST_CODE_LIST}");
List<Snippet> sugs = getJeddictChatModel(fileObject).suggestNextLineCode(updateddoc, line, mimeType);
for (Snippet varName : sugs) {
resultSet.addItem(createItem(varName, line, lineTextBeforeCaret, javaToken, null, doc));
SQLEditorSupport sQLEditorSupport = fileObject.getLookup().lookup(SQLEditorSupport.class);
if (sQLEditorSupport != null) {
SQLCompletion sqlCompletion = new SQLCompletion(sQLEditorSupport);
String updateddoc = insertPlaceholderAtCaret(doc, caretOffset, "${SUGGEST_SQL_QUERY_LIST}");
List<Snippet> sugs = getJeddictChatModel(fileObject).suggestSQLQuery(sqlCompletion.getMetaData(), updateddoc);
for (Snippet varName : sugs) {
resultSet.addItem(createItem(varName, line, lineTextBeforeCaret, javaToken, null, doc));
}
} else {
String updateddoc = insertPlaceholderAtCaret(doc, caretOffset, "${SUGGEST_CODE_LIST}");
List<Snippet> sugs = getJeddictChatModel(fileObject).suggestNextLineCode(updateddoc, line, mimeType);
for (Snippet varName : sugs) {
resultSet.addItem(createItem(varName, line, lineTextBeforeCaret, javaToken, null, doc));
}
}
}
} catch (Exception e) {
Expand All @@ -512,6 +520,7 @@ && trimLeadingSpaces(line).charAt(0) == '@') || kind == Tree.Kind.ANNOTATION) {
}
}


private static boolean isJavaIdentifierPart(String text, boolean allowForDor) {
for (int i = 0; i < text.length(); i++) {
if (!(Character.isJavaIdentifierPart(text.charAt(i)) || allowForDor && text.charAt(i) == '.')) {
Expand Down Expand Up @@ -547,7 +556,7 @@ public static JavaToken isJavaContext(final Document doc, final int offset, fina
if (offset == ts.offset()) {
return new JavaToken(true, ts.token().id(), ts.offset());
}

switch (ts.token().id()) {
case DOUBLE_LITERAL:
case FLOAT_LITERAL:
Expand All @@ -573,5 +582,5 @@ public static JavaToken isJavaContext(final Document doc, final int offset, fina
}
}
}

}
Loading

0 comments on commit eba4136

Please sign in to comment.