chatbot enhancements

This commit is contained in:
Bane Stojkovic
2025-04-02 00:11:16 +02:00
parent 3c48e498c2
commit 74946f6bce
4 changed files with 259 additions and 26 deletions
@@ -5,9 +5,18 @@ import static org.mockito.Mockito.*;
import java.awt.Point; import java.awt.Point;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.thoughtworks.xstream.XStream;
import org.diylc.common.ComponentType; import org.diylc.common.ComponentType;
import org.diylc.common.IComponentTransformer; import org.diylc.common.IComponentTransformer;
import org.diylc.common.PropertyWrapper; import org.diylc.common.PropertyWrapper;
+6
View File
@@ -112,6 +112,12 @@
<artifactId>slf4j-simple</artifactId> <artifactId>slf4j-simple</artifactId>
<version>1.7.36</version> <version>1.7.36</version>
</dependency> </dependency>
<!-- Jackson for JSON processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
</dependency>
<dependency> <dependency>
<groupId>com.oracle</groupId> <groupId>com.oracle</groupId>
<artifactId>appbundler</artifactId> <artifactId>appbundler</artifactId>
@@ -3,18 +3,13 @@ package org.diylc.swing.plugins.chatbot;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask; import org.diylc.common.ITask;
import org.diylc.core.IView;
import org.diylc.plugins.chatbot.presenter.ChatbotPresenter; import org.diylc.plugins.chatbot.presenter.ChatbotPresenter;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.plugins.cloud.presenter.NotLoggedInException;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
import org.diylc.swing.plugins.config.ConfigPlugin;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File; import java.io.File;
import java.util.Random;
public class ChatbotPane extends JPanel { public class ChatbotPane extends JPanel {
@@ -22,6 +17,93 @@ public class ChatbotPane extends JPanel {
private static final Logger LOG = Logger.getLogger(ChatbotPane.class); private static final Logger LOG = Logger.getLogger(ChatbotPane.class);
public static final String ASSISTANT = "assistant";
public static final String SYSTEM = "system";
public static final String USER = "user";
public static final String TEMPORARY = "temporary";
String[] electronicsQuestions = {
"What is Ohm's Law, and how do voltage, current, and resistance relate to each other?",
"Why are resistors important in circuits, and what happens if the resistor value is incorrect?",
"What is a capacitor, and how does it behave differently from a resistor?",
"How does an inductor work, and where might you find one in common DIY projects?",
"What's the difference between AC (Alternating Current) and DC (Direct Current), and where is each used?",
"How do diodes work, and why are they essential in electronics?",
"What's the difference between series and parallel circuits, and why does it matter?",
"How does a transistor function, and what role does it typically play in a circuit?",
"Why is grounding important in electronic circuits, and what exactly does it do?",
"What is impedance, and why is it important when connecting speakers or audio equipment?",
"What exactly is an operational amplifier (op amp), and what are its common uses in audio circuits?",
"How does a relay work, and when would you choose a relay over a transistor or MOSFET?",
"What's the purpose of using a fuse or circuit breaker in a DIY electronics project?",
"Why do certain electronic components need specific voltage ratings?",
"What is electromagnetic interference (EMI), and how can you minimize it in your projects?",
"What does polarity mean for components like electrolytic capacitors and diodes, and why is it important?",
"How does filtering work to remove unwanted noise from audio signals or power supplies?",
"What is signal clipping in audio circuits, and how can you prevent it?",
"Why do some circuits require a heatsink, and how do heatsinks help protect components?",
"What is frequency response, and why is it crucial for audio circuits like guitar pedals and amplifiers?",
"How do you calculate the correct resistor value for limiting current to an LED?",
"What is the role of a voltage regulator, and how does it keep voltage stable?",
"How can you measure and verify voltage and current safely using a multimeter?",
"What does it mean when a circuit is described as having a 'high input impedance' or 'low output impedance,' and why does it matter?",
"How can you determine if components in your circuit are properly rated for the voltage and current they're experiencing?"
};
String[] diylcQuestions = {
"How do I add a component to my layout in DIYLC?",
"How can I quickly find a specific component in DIYLC?s component toolbox?",
"How do I move or reposition components on the canvas in DIYLC?",
"How do I edit or change a component?s properties (e.g. value or color) in DIYLC?",
"Is there a shortcut to duplicate or repeat the last component I placed in DIYLC?",
"How can I group multiple components so I can move or edit them together in DIYLC?",
"What are ?building blocks? in DIYLC and how do I create or use them?",
"How do I save my DIYLC project and reopen it later on?",
"How do I export my DIYLC layout as an image or PDF file?",
"Can DIYLC generate a bill of materials (BOM) for my project, and how would I do that?",
"How can I change or hide different layers in a DIYLC project to manage overlapping components?",
"Is it possible to view the underside of a board in DIYLC, and how can I enable that?",
"What does the ?Highlight Connected Areas? feature do in DIYLC and how do I use it for debugging?",
"How can I analyze a guitar wiring diagram using DIYLC?s built-in tools?",
"How do I assign a custom keyboard shortcut to a component in DIYLC for quick access?",
"What are component variants in DIYLC and how can I create and apply them?",
"What is the continuous creation mode in DIYLC and how does it help when adding many components?",
"How can I create a custom component to add to DIYLC?s component library?",
"Does DIYLC support plug-ins, and how can I add new functionality to the app with them?",
"What is the DIYLC cloud feature and how can I share or download projects using it?"
};
String[] circuitQuestions = {
"What's the purpose of this specific resistor in my circuit?",
"How do I correctly determine capacitor values for my power supply?",
"How should I route wiring to reduce interference and noise?",
"Which component should I choose for this switching application, a MOSFET or BJT?",
"How do I verify if my ground connections are optimal?",
"Why might this transistor get hot during operation?",
"What's the best approach to simplify this section of my circuit?",
"How can I ensure my circuit is safe against short circuits?",
"What could be causing voltage instability in this circuit?",
"How do I properly size resistors to protect LEDs?",
"What are the steps to debug unexpected oscillations in my circuit?",
"Should I add a bypass capacitor here, and what value should I use?",
"How can I check if my components are operating within their rated specifications?",
"Is this the right way to connect multiple power rails in my design?",
"How can I test my circuit before physically assembling it?",
"What are good layout practices to minimize electromagnetic interference?",
"How do I identify if my circuit has any redundant or unnecessary components?",
"Why might the voltage regulator not output the expected voltage?",
"What's the recommended method for isolating digital and analog grounds?",
"How do I safely integrate high-voltage components into my DIY circuit?",
"Why isn't my LED lighting up when powered?",
"How do I troubleshoot a circuit that's drawing more current than expected?",
"Why does my amplifier circuit produce a humming or buzzing sound?",
"How can I detect and fix intermittent connections in my circuit?",
"What should I check if my circuit isn't responding to input signals as expected?",
"How do I determine if my soldering joints are causing reliability issues?",
"What steps can I take if my microcontroller circuit isn't functioning as intended?",
"How do I troubleshoot a noisy or unstable sensor reading?"
};
public static Font DEFAULT_FONT = new Font("Square721 BT", Font.PLAIN, 12); public static Font DEFAULT_FONT = new Font("Square721 BT", Font.PLAIN, 12);
private static final Font MONOSPACED_FONT = new Font("Monospaced", Font.PLAIN, 12); private static final Font MONOSPACED_FONT = new Font("Monospaced", Font.PLAIN, 12);
private static final Color TERMINAL_BG = new Color(40, 40, 40); private static final Color TERMINAL_BG = new Color(40, 40, 40);
@@ -129,6 +211,19 @@ public class ChatbotPane extends JPanel {
promptArea.setForeground(TERMINAL_FG); promptArea.setForeground(TERMINAL_FG);
promptArea.setCaretColor(TERMINAL_FG); promptArea.setCaretColor(TERMINAL_FG);
// Add Enter key handling
promptArea.addKeyListener(new java.awt.event.KeyAdapter() {
@Override
public void keyPressed(java.awt.event.KeyEvent e) {
if (e.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER && !e.isShiftDown()) {
e.consume(); // Prevent the newline from being added
if (getAskButton().isEnabled()) {
getAskButton().doClick();
}
}
}
});
// Calculate height based on font metrics // Calculate height based on font metrics
int lineHeight = promptArea.getFontMetrics(promptArea.getFont()).getHeight(); int lineHeight = promptArea.getFontMetrics(promptArea.getFont()).getHeight();
int desiredHeight = lineHeight * 3 + 10; // 3 lines + padding int desiredHeight = lineHeight * 3 + 10; // 3 lines + padding
@@ -207,33 +302,36 @@ public class ChatbotPane extends JPanel {
".user { color: #98C379; }" + // Softer green that's easier on the eyes ".user { color: #98C379; }" + // Softer green that's easier on the eyes
".assistant { color: #61AFEF; }" + // Lighter, more vibrant blue ".assistant { color: #61AFEF; }" + // Lighter, more vibrant blue
".system { color: #E5C07B; }" + // Warmer, muted yellow ".system { color: #E5C07B; }" + // Warmer, muted yellow
".temporary { color: #555555; }" +
"</style>", "</style>",
MONOSPACED_FONT.getFamily(), MONOSPACED_FONT.getFamily(),
MONOSPACED_FONT.getSize(), MONOSPACED_FONT.getSize(),
TERMINAL_FG.getRed(), TERMINAL_FG.getGreen(), TERMINAL_FG.getBlue(), TERMINAL_FG.getRed(), TERMINAL_FG.getGreen(), TERMINAL_FG.getBlue(),
TERMINAL_BG.getRed(), TERMINAL_BG.getGreen(), TERMINAL_BG.getBlue()); TERMINAL_BG.getRed(), TERMINAL_BG.getGreen(), TERMINAL_BG.getBlue());
// Sample chat history String sampleChat = getSampleChat();
String sampleChat =
"<div class='system'>Welcome to DIYLC AI Assistant! How can I help you today?</div>\n\n" +
"<div class='user'>How do I create a simple circuit?</div>\n\n" +
"<div class='assistant'>To create a simple circuit:\n" +
"1. Drag components from the component panel\n" +
"2. Connect them by dragging from one terminal to another\n" +
"3. Use the grid to align components neatly</div>\n\n" +
"<div class='user'>What's the best way to organize components?</div>\n\n" +
"<div class='assistant'>For best organization:\n" +
"- Group related components together\n" +
"- Use consistent spacing\n" +
"- Label important connections\n" +
"- Consider signal flow direction</div>";
chatEditorPane.setContentType("text/html"); chatEditorPane.setContentType("text/html");
chatEditorPane.setText(htmlStyle + "<body><pre>" + sampleChat + "</pre></body>"); chatEditorPane.setText(htmlStyle + "<body><pre>" + sampleChat + "</pre></body>");
} }
return chatEditorPane; return chatEditorPane;
} }
private String getSampleChat() {
Random r = new Random();
return
"<div class='system'>Welcome to the DIYLC AI Assistant!</div><br><br>\n" +
"<div class='assistant'>I'm here to help you design, build, and troubleshoot your electronics projects using DIY Layout Creator (DIYLC). You can ask me questions about:</div><br>\n" +
"<ul>\n" +
" <li><b>Electronics theory or concepts:</b> <i>e.g.,</i> '<span class='user'>" + electronicsQuestions[r.nextInt(
electronicsQuestions.length)] + "</span>'</li>\n" +
" <li><b>DIYLC features and usage:</b> <i>e.g.,</i> '<span class='user'>" + diylcQuestions[r.nextInt(diylcQuestions.length)] + "</span>'</li>\n" +
" <li><b>Your current circuit project:</b> <i>e.g.,</i> '<span class='user'>" + circuitQuestions[r.nextInt(circuitQuestions.length)] + "</span>'</li>\n" +
"</ul><br>\n" +
"<div class='assistant'>Feel free to ask your own question or use one of these examples to get started!</div><br>";
}
public JButton getAskButton() { public JButton getAskButton() {
if (askButton == null) { if (askButton == null) {
askButton = new JButton("Ask"); askButton = new JButton("Ask");
@@ -243,7 +341,8 @@ public class ChatbotPane extends JPanel {
askButton.setBorderPainted(true); askButton.setBorderPainted(true);
askButton.addActionListener(e -> { askButton.addActionListener(e -> {
final String prompt = getPromptArea().getText(); final String prompt = getPromptArea().getText();
appendSection("user", prompt); appendSection(USER, prompt);
appendSection(TEMPORARY, "Waiting for the response...");
getPromptArea().setText(null); getPromptArea().setText(null);
String currentFile = plugInPort.getCurrentFileName(); String currentFile = plugInPort.getCurrentFileName();
String fileName = extractFileName(currentFile); String fileName = extractFileName(currentFile);
@@ -259,14 +358,14 @@ public class ChatbotPane extends JPanel {
@Override @Override
public void failed(Exception e) { public void failed(Exception e) {
appendSection("system", "Failed to retrieve the response from the server. Error: " + e.getMessage()); appendSection(SYSTEM, "Failed to retrieve the response from the server. Error: " + e.getMessage());
LOG.error("Failed to retrieve the response from the server", e); LOG.error("Failed to retrieve the response from the server", e);
getClearButton().setEnabled(true); getClearButton().setEnabled(true);
} }
@Override @Override
public void complete(String result) { public void complete(String result) {
appendSection("assistant", result); appendSection(ASSISTANT, result);
getClearButton().setEnabled(true); getClearButton().setEnabled(true);
} }
}, true); }, true);
@@ -277,9 +376,13 @@ public class ChatbotPane extends JPanel {
private void appendSection(String style, String insertText) { private void appendSection(String style, String insertText) {
String text = getChatEditorPane().getText(); String text = getChatEditorPane().getText();
// remove any temporary divs
String regex = "(?s)<div\\s+class=[\"']temporary[\"'][^>]*>.*?</div>\\s*<br>\\s*";
text = text.replaceAll(regex, "");
// add a new div
int bodyCloseIndex = text.indexOf("</body>"); int bodyCloseIndex = text.indexOf("</body>");
text = text.substring(0, bodyCloseIndex) + text = text.substring(0, bodyCloseIndex) +
"\n<div class='" + style + "'>" + insertText + "</div>\n" + "\n<div class='" + style + "'>" + insertText + "</div><br>" +
text.substring(bodyCloseIndex); text.substring(bodyCloseIndex);
getChatEditorPane().setText(text); getChatEditorPane().setText(text);
} }
@@ -0,0 +1,115 @@
package org.diylc;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.diylc.common.ComponentType;
import org.diylc.presenter.ComponentProcessor;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ComponentTypeDumpTest {
// @Test
public void dumpComponentTypesToKnowledgeBaseSQLFile() {
Map<String, List<ComponentType>> componentTypes =
ComponentProcessor.getInstance().getComponentTypes();
List<DIYLCComponentType> components = componentTypes.values().stream()
.flatMap(x -> x.stream())
.map(x -> new DIYLCComponentType(x.getName(), x.getDescription(), x.getCategory(),
ComponentProcessor.getInstance().extractProperties(x.getInstanceClass()).stream()
.map(y -> new DIYLCProperty(y.getName(), formatType(y.getType())))
.toList()))
.toList();
try (PrintWriter writer = new PrintWriter(new File("/users/branislavstojkovic/downloads/test.sql"))) {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
for (DIYLCComponentType component : components) {
String section = "Component Type: " + component.getName();
String escapedSection = section.replace("'", "''");
// First delete any existing record for this component type
String deleteSql = String.format(
"DELETE FROM diylc_knowledge_base WHERE section = '%s';\n",
escapedSection
);
writer.write(deleteSql);
// Then insert the new record
String content = mapper.writeValueAsString(component);
content = content.replace("'", "''");
String insertSql = String.format(
"INSERT INTO diylc_knowledge_base (section, content) VALUES ('%s', '%s');\n",
escapedSection,
content
);
writer.write(insertSql);
}
} catch (IOException e) {
throw new RuntimeException("Failed to write SQL file", e);
}
}
private String formatType(Class<?> type) {
if (type.isEnum()) {
String enumValues = Arrays.stream(type.getEnumConstants())
.map(Object::toString)
.collect(Collectors.joining(","));
return type.getName() + "(" + enumValues + ")";
}
return type.getName();
}
@JsonInclude(JsonInclude.Include.NON_NULL)
static class DIYLCProperty {
private String name;
private String type;
public DIYLCProperty(String name, String type) {
this.name = name;
this.type = type;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
}
@JsonInclude(JsonInclude.Include.NON_NULL)
private static class DIYLCComponentType {
private String name;
private String description;
private String category;
private List<DIYLCProperty> properties;
public DIYLCComponentType(String name, String description, String category,
List<DIYLCProperty> properties) {
this.name = name;
this.description = description;
this.category = category;
this.properties = properties;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public List<DIYLCProperty> getProperties() { return properties; }
public void setProperties(List<DIYLCProperty> properties) { this.properties = properties; }
}
}