Skip to content

Commit

Permalink
MARP-747 Improve the explanatory dialog and pimp the documentation. (#77
Browse files Browse the repository at this point in the history
)

---------
Co-authored-by: linhpd-axonivy <[email protected]>
Co-authored-by: Dinh Nguyen <[email protected]>
  • Loading branch information
ntqdinh-axonivy authored Nov 20, 2024
1 parent c3c0b7b commit 86cd5ca
Show file tree
Hide file tree
Showing 14 changed files with 347 additions and 113 deletions.
3 changes: 3 additions & 0 deletions openai-assistant-product/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ The following keys are valid and interpreted:
```
@variables.yaml@
```

### Note
Make sure to enable the `Show Only Source Page` option under `Window` -> `Preferences` -> `Axon Ivy` -> `Html Dialog Editor` -> `Show Only Source Page` to prevent unexpected behavior.
3 changes: 3 additions & 0 deletions openai-assistant-product/README_DE.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ The following keys are valid and interpreted:
@variables.yaml@
```

### Note
Make sure to enable the `Show Only Source Page` option under `Window` -> `Preferences` -> `Axon Ivy` -> `Html Dialog Editor` -> `Show Only Source Page` to prevent unexpected behavior.

Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,19 @@ public String getModels() {
}

public String ask(String context, String question) {
return sendRequest(context, question, false);
}

public String insert(String context, String question) {
return sendRequest(context, question, true);
}

private String sendRequest(String context, String question, boolean includeSystemPrompt) {
WebTarget chat = client.get().path("chat/completions");
ArrayNode arrayNode = JsonNodeFactory.instance.arrayNode();
arrayNode.add(message("system", SYSTEM_PROMPT));
if (includeSystemPrompt) {
arrayNode.add(message("system", SYSTEM_PROMPT));
}
arrayNode.add(message("user", String.format("%s \n\n %s", context, question)));
ObjectNode request = completion().set("messages", arrayNode);
var payload = Entity.entity(request, MediaType.APPLICATION_JSON);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void run() {
String insert = SwtCommonDialogs.openInputDialog(site.getShell(), "any wishes?", "what can Chat GPT do for you?",
"insert a combobox to pick a brand out of: Mercedes, BMW or Tesla");
if (insert != null) {
var response = runWithProgress(()->chatGpt.ask(what, insert));
var response = runWithProgress(() -> chatGpt.insert(what, insert));
diffResult(response);
}
return;
Expand Down Expand Up @@ -99,11 +99,10 @@ public void run() {
return;
}
}

boolean assist = SwtCommonDialogs.openQuestionDialog(site.getShell(), "need assistance?", """
ready for asking chat GPT on ?
"""+quest+": \n"+abbrev(what));
if (assist) {
var message = String.format("```\n%s\n```", centerAbbrev(what));
var dialog = new QuestionDialog(site.getShell(), String.format("%s Code Snippet", capitalize(quest)), message);
dialog.open();
if (dialog.isAgreed()) {
var response = runWithProgress(()->chatGpt.ask(what, quest));
if (quest.equalsIgnoreCase(Quests.FIX)) {
response = diffResult(response);
Expand All @@ -113,6 +112,10 @@ public void run() {
}
}

private String capitalize(String text) {
return text.substring(0, 1).toUpperCase() + text.substring(1);
}

private String runWithProgress(Supplier<String> gptAction) {
var response = new AtomicReference<String>();
run(pm -> {
Expand Down Expand Up @@ -180,6 +183,15 @@ private static String abbrev(String what) {
return what;
}

private static String centerAbbrev(String what) {
int limit = 500;
if (what.length() > limit) {
int halfLimit = (limit - 3) / 2;
return what.substring(0, halfLimit) + "\n" + "..." + "\n" + what.substring(what.length() - halfLimit);
}
return what;
}

private Optional<String> getSelectedText() {
if (selected instanceof TextSelection text) {
return Optional.of(text.getText());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,107 +1,17 @@
package com.axonivy.connector.openai.assistant.ui;

import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.JFacePreferences;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;

public class CopyableInfoDialog extends Dialog {
public class CopyableInfoDialog extends MarkdownDialog {

private static final int COPY_TO_CLIPBOARD_ID = 1;
private static final String HEX_COLOR_FORMAT = "#%02x%02x%02x";
private String title;
private String message;
private Browser browser;

public CopyableInfoDialog(Shell parentShell, String title, String message) {
super(parentShell);
this.title = title;
this.message = message;
}

@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(title);
newShell.setMinimumSize(750, 400);
}

@Override
protected Point getInitialSize() {
return new Point(750, 400);
}

@Override
protected Point getInitialLocation(Point initialSize) {
Rectangle screenSize = getShell().getDisplay().getPrimaryMonitor().getBounds();

// Calculate the center position
int x = (screenSize.width - initialSize.x) / 2;
int y = (screenSize.height - initialSize.y) / 2;

return new Point(x, y);
}

@Override
protected boolean isResizable() {
return true;
}

@Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
container.setLayout(new GridLayout(1, false));

browser = new Browser(container, SWT.BORDER);
browser.setLayoutData(new GridData(GridData.FILL_BOTH));

Parser parser = Parser.builder().build();
HtmlRenderer renderer = HtmlRenderer.builder().build();
String htmlContent = renderer.render(parser.parse(this.message));

// Get Eclipse theme colors
Color bgColor = JFaceResources.getColorRegistry().get(JFacePreferences.CONTENT_ASSIST_BACKGROUND_COLOR);
Color fgColor = JFaceResources.getColorRegistry().get(JFacePreferences.CONTENT_ASSIST_FOREGROUND_COLOR);

// Create CSS with Eclipse colors
String css = String.format("body { background-color: %s; color: %s; font-family: '%s'; }", toHex(bgColor.getRGB()),
toHex(fgColor.getRGB()), JFaceResources.getTextFont().getFontData()[0].getName());

// Wrap HTML content with custom CSS
String htmlWithCss = String.format("<html><head><style>%s</style></head><body>%s</body></html>", css, htmlContent);

browser.setText(htmlWithCss);

browser.addProgressListener(new ProgressListener() {
@Override
public void completed(ProgressEvent event) {
getShell().getDisplay().asyncExec(() -> resizeDialog());
}

@Override
public void changed(ProgressEvent event) {
// Not needed for this implementation
}
});

return container;
super(parentShell, title, message);
}

@Override
Expand All @@ -125,15 +35,4 @@ private void copyToClipboard() {
clipboard.setContents(new Object[] { message }, new Transfer[] { textTransfer });
clipboard.dispose();
}

private String toHex(RGB rgb) {
return String.format(HEX_COLOR_FORMAT, rgb.red, rgb.green, rgb.blue);
}

private void resizeDialog() {
Shell shell = getShell();
Point preferredSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
shell.setSize(preferredSize);
shell.layout(true, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.axonivy.connector.openai.assistant.ui;

import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.JFacePreferences;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;

public abstract class MarkdownDialog extends Dialog {

private static final String HEX_COLOR_FORMAT = "#%02x%02x%02x";
protected String title;
protected String message;
protected Browser browser;

public MarkdownDialog(Shell parentShell, String title, String message) {
super(parentShell);
this.title = title;
this.message = message;
}

@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(title);
newShell.setMinimumSize(750, 400);
}

@Override
protected Point getInitialSize() {
return new Point(750, 400);
}

@Override
protected Point getInitialLocation(Point initialSize) {
Rectangle screenSize = getShell().getDisplay().getPrimaryMonitor().getBounds();

// Calculate the center position
int x = (screenSize.width - initialSize.x) / 2;
int y = (screenSize.height - initialSize.y) / 2;

return new Point(x, y);
}

@Override
protected boolean isResizable() {
return true;
}

@Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
container.setLayout(new GridLayout(1, false));

browser = new Browser(container, SWT.BORDER);
browser.setLayoutData(new GridData(GridData.FILL_BOTH));

Parser parser = Parser.builder().build();
HtmlRenderer renderer = HtmlRenderer.builder().build();
String htmlContent = renderer.render(parser.parse(this.message));

// Wrap HTML content with custom CSS
String htmlWithCss = String.format("<html><head><style>%s</style></head><body>%s</body></html>", getEclipseCss(),
htmlContent);

browser.setText(htmlWithCss);

browser.addProgressListener(new ProgressListener() {
@Override
public void completed(ProgressEvent event) {
getShell().getDisplay().asyncExec(() -> resizeDialog());
}

@Override
public void changed(ProgressEvent event) {
// Not needed for this implementation
}
});

return container;
}

private String getEclipseCss() {
// Get Eclipse theme colors
Color fgColor = JFaceResources.getColorRegistry().get(JFacePreferences.CONTENT_ASSIST_FOREGROUND_COLOR);
Color bgColor = JFaceResources.getColorRegistry().get(JFacePreferences.CONTENT_ASSIST_BACKGROUND_COLOR);
return String.format("body { background-color: %s; color: %s; font-family: '%s'; }", toHex(bgColor.getRGB()),
toHex(fgColor.getRGB()), JFaceResources.getTextFont().getFontData()[0].getName());
}

private String toHex(RGB rgb) {
return String.format(HEX_COLOR_FORMAT, rgb.red, rgb.green, rgb.blue);
}

private void resizeDialog() {
Shell shell = getShell();
Point preferredSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
shell.setSize(preferredSize);
shell.layout(true, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.axonivy.connector.openai.assistant.ui;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;

public class QuestionDialog extends MarkdownDialog {

private int buttonId;

public QuestionDialog(Shell parentShell, String title, String message) {
super(parentShell, title, message);
}
@Override
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.YES_ID, IDialogConstants.YES_LABEL, true);
createButton(parent, IDialogConstants.NO_ID, IDialogConstants.NO_LABEL, false);
}

@Override
protected void buttonPressed(int buttonId) {
this.buttonId = buttonId;
super.buttonPressed(OK);
}

public boolean isAgreed() {
return buttonId == IDialogConstants.YES_ID;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ public class MockAI {
"completions", json(load("completions.json")),
"completions-response", json(load("completions-response.json")),
"mail-generator", json(load("mail-generator.json")),
"mail-generator-response", json(load("mail-generator-response.json"))
);
"mail-generator-response", json(load("mail-generator-response.json")),
"assist-ask-without-system-promt", json(load("assist-ask-without-system-promt.json")),
"assist-ask-without-system-promt-response", json(load("assist-ask-without-system-promt-response.json")),
"assist-insert-with-system-promt", json(load("assist-insert-with-system-promt.json")),
"assist-insert-with-system-promt-response", json(load("assist-insert-with-system-promt-response.json")));

@POST
@Path("completions")
Expand Down Expand Up @@ -89,7 +92,7 @@ private String input(JsonNode request, Map<String, JsonNode> examples) {
return null;
}

@POST
@POST
@Path("chat/completions")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
Expand Down
Loading

0 comments on commit 86cd5ca

Please sign in to comment.