mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 17:22:09 +10:00
chatbot enhancements
This commit is contained in:
@@ -57,6 +57,11 @@
|
|||||||
<artifactId>reflections</artifactId>
|
<artifactId>reflections</artifactId>
|
||||||
<version>0.10.2</version>
|
<version>0.10.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.16.1</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
|||||||
@@ -50,11 +50,10 @@ public interface INetlistAnalyzer {
|
|||||||
* Summarizes all {@link Netlist}s provided.
|
* Summarizes all {@link Netlist}s provided.
|
||||||
*
|
*
|
||||||
* @param netlists
|
* @param netlists
|
||||||
* @param preferredOutput optional, needed only where there's more than one possible output node.
|
|
||||||
* @return
|
* @return
|
||||||
* @throws TreeException
|
* @throws TreeException
|
||||||
*/
|
*/
|
||||||
List<Summary> summarize(List<Netlist> netlists, Node preferredOutput) throws TreeException;
|
List<Summary> summarize(List<Netlist> netlists) throws TreeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return name of the font to be used for display.
|
* @return name of the font to be used for display.
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ public abstract class AbstractNetlistAnalyzer {
|
|||||||
|
|
||||||
public AbstractNetlistAnalyzer() {}
|
public AbstractNetlistAnalyzer() {}
|
||||||
|
|
||||||
public List<Summary> summarize(List<Netlist> netlists, Node preferredOutput) throws TreeException {
|
public List<Summary> summarize(List<Netlist> netlists) throws TreeException {
|
||||||
Map<String, Summary> summaries = new HashMap<String, Summary>();
|
Map<String, Summary> summaries = new HashMap<String, Summary>();
|
||||||
for (Netlist n : netlists) {
|
for (Netlist n : netlists) {
|
||||||
Summary s = summarize(n, preferredOutput);
|
Summary s = summarize(n);
|
||||||
if (summaries.containsKey(s.getSummary()))
|
if (summaries.containsKey(s.getSummary()))
|
||||||
summaries.get(s.getSummary()).append(n);
|
summaries.get(s.getSummary()).append(n);
|
||||||
else
|
else
|
||||||
@@ -46,7 +46,7 @@ public abstract class AbstractNetlistAnalyzer {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException;
|
protected abstract Summary summarize(Netlist netlist) throws TreeException;
|
||||||
|
|
||||||
public Tree constructTreeBetween(Netlist netlist, Node nodeA, Node nodeB) {
|
public Tree constructTreeBetween(Netlist netlist, Node nodeA, Node nodeB) {
|
||||||
Tree tree = new Tree(TreeConnectionType.Parallel);
|
Tree tree = new Tree(TreeConnectionType.Parallel);
|
||||||
|
|||||||
+207
-7
@@ -23,10 +23,19 @@ package org.diylc.plugins.chatbot.presenter;
|
|||||||
|
|
||||||
import com.diyfever.httpproxy.PhpFlatProxy;
|
import com.diyfever.httpproxy.PhpFlatProxy;
|
||||||
import com.diyfever.httpproxy.ProxyFactory;
|
import com.diyfever.httpproxy.ProxyFactory;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.checkerframework.checker.units.qual.C;
|
||||||
import org.checkerframework.checker.units.qual.N;
|
import org.checkerframework.checker.units.qual.N;
|
||||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||||
|
import org.diylc.common.ComponentType;
|
||||||
|
import org.diylc.common.IPlugInPort;
|
||||||
import org.diylc.common.PropertyWrapper;
|
import org.diylc.common.PropertyWrapper;
|
||||||
|
import org.diylc.core.IDIYComponent;
|
||||||
|
import org.diylc.netlist.Group;
|
||||||
|
import org.diylc.netlist.Netlist;
|
||||||
|
import org.diylc.netlist.NetlistException;
|
||||||
import org.diylc.plugins.chatbot.model.IChatbotAPI;
|
import org.diylc.plugins.chatbot.model.IChatbotAPI;
|
||||||
import org.diylc.plugins.cloud.model.CommentEntity;
|
import org.diylc.plugins.cloud.model.CommentEntity;
|
||||||
import org.diylc.plugins.cloud.model.IServiceAPI;
|
import org.diylc.plugins.cloud.model.IServiceAPI;
|
||||||
@@ -38,16 +47,22 @@ import org.diylc.plugins.cloud.presenter.NotLoggedInException;
|
|||||||
import org.diylc.presenter.ComparatorFactory;
|
import org.diylc.presenter.ComparatorFactory;
|
||||||
import org.diylc.presenter.ComponentProcessor;
|
import org.diylc.presenter.ComponentProcessor;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.ReadableByteChannel;
|
import java.nio.channels.ReadableByteChannel;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.diylc.utils.FileUtils.extractFileName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all the back-end logic for using the cloud and manipulating projects on the cloud.
|
* Contains all the back-end logic for using the cloud and manipulating projects on the cloud.
|
||||||
@@ -56,17 +71,19 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class ChatbotPresenter {
|
public class ChatbotPresenter {
|
||||||
|
|
||||||
public static final ChatbotPresenter Instance = new ChatbotPresenter();
|
|
||||||
|
|
||||||
private static String ERROR = "Error";
|
private static String ERROR = "Error";
|
||||||
|
|
||||||
private final static Logger LOG = Logger.getLogger(ChatbotPresenter.class);
|
private final static Logger LOG = Logger.getLogger(ChatbotPresenter.class);
|
||||||
private static final Object SUCCESS = "Success";
|
private static final Object SUCCESS = "Success";
|
||||||
|
private final IPlugInPort plugInPort;
|
||||||
|
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
private IChatbotAPI service;
|
private IChatbotAPI service;
|
||||||
private String serviceUrl;
|
private String serviceUrl;
|
||||||
|
|
||||||
private ChatbotPresenter() {}
|
public ChatbotPresenter(IPlugInPort plugInPort) {
|
||||||
|
this.plugInPort = plugInPort;
|
||||||
|
}
|
||||||
|
|
||||||
private IChatbotAPI getService() {
|
private IChatbotAPI getService() {
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
@@ -78,10 +95,193 @@ public class ChatbotPresenter {
|
|||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String promptChatbot(String project, String netlist, String prompt) throws NotLoggedInException {
|
public String promptChatbot(String prompt) throws NotLoggedInException {
|
||||||
if (!CloudPresenter.Instance.isLoggedIn())
|
if (!CloudPresenter.Instance.isLoggedIn())
|
||||||
throw new NotLoggedInException();
|
throw new NotLoggedInException();
|
||||||
return getService().promptChatbot(CloudPresenter.Instance.getCurrentUsername(), CloudPresenter.Instance.getCurrentToken(),
|
|
||||||
CloudPresenter.Instance.getMachineId(), project, netlist, prompt);
|
String currentFile = plugInPort.getCurrentFileName();
|
||||||
|
String fileName = extractFileName(currentFile);
|
||||||
|
|
||||||
|
String netlist;
|
||||||
|
try {
|
||||||
|
netlist = extractNetlists();
|
||||||
|
} catch (NetlistException e) {
|
||||||
|
LOG.error("Error extracting netlist", e);
|
||||||
|
netlist = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getService().promptChatbot(CloudPresenter.Instance.getCurrentUsername(),
|
||||||
|
CloudPresenter.Instance.getCurrentToken(),
|
||||||
|
CloudPresenter.Instance.getMachineId(), fileName, netlist, prompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Set<Class<?>> PROPERTY_TYPES_TO_SKIP = Set.of(Font.class, Color.class);
|
||||||
|
|
||||||
|
private String extractNetlists() throws NetlistException {
|
||||||
|
List<Netlist> netlists = plugInPort.extractNetlists(true);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Components: ");
|
||||||
|
|
||||||
|
Set<? extends IDIYComponent<?>> components = netlists.stream().flatMap(n -> n.getGroups().stream()
|
||||||
|
.flatMap(g -> g.getNodes().stream().map(node -> node.getComponent())))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
List<Map<String, Object>> componentDescriptors = new ArrayList<>();
|
||||||
|
|
||||||
|
components.forEach(c -> {
|
||||||
|
ComponentType componentType = ComponentProcessor.getInstance()
|
||||||
|
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||||
|
List<PropertyWrapper> properties =
|
||||||
|
ComponentProcessor.getInstance().extractProperties(c.getClass());
|
||||||
|
|
||||||
|
Map<String, Object> componentDescriptorMap = new HashMap<>();
|
||||||
|
componentDescriptorMap.put("name", c.getName());
|
||||||
|
componentDescriptorMap.put("type", componentType.getName());
|
||||||
|
componentDescriptorMap.put("category", componentType.getCategory());
|
||||||
|
|
||||||
|
properties.forEach(p -> {
|
||||||
|
if (PROPERTY_TYPES_TO_SKIP.contains(p.getType()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
p.readFrom(c);
|
||||||
|
if (p.getValue() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
componentDescriptorMap.put(p.getName(), p.getValue().toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn("Error extracting properties", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
componentDescriptors.add(componentDescriptorMap);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
String json = MAPPER.writeValueAsString(componentDescriptors);
|
||||||
|
sb.append(json).append("\n\n");
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Failed to serialize component descriptors to JSON", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Netlist netlist : netlists) {
|
||||||
|
sb.append("Switch configuration: ").append(netlist.getSwitchSetup()).append("\n\n")
|
||||||
|
.append("Connected node groups:\n\n");
|
||||||
|
for (Group v : netlist.getSortedGroups()) {
|
||||||
|
sb.append(v.getSortedNodes()).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInitialChatContents() {
|
||||||
|
Random r = new Random();
|
||||||
|
|
||||||
|
String chatHtml =
|
||||||
|
"<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" +
|
||||||
|
"\n" +
|
||||||
|
"- <b>Electronics theory or concepts:</b> <i>e.g.,</i> '<span class='user'>" + electronicsQuestions[r.nextInt(
|
||||||
|
electronicsQuestions.length)] + "</span>'<br>\n" +
|
||||||
|
"- <b>DIYLC features and usage:</b> <i>e.g.,</i> '<span class='user'>" + diylcQuestions[r.nextInt(diylcQuestions.length)] + "</span>'<br>\n" +
|
||||||
|
"- <b>Your current circuit project:</b> <i>e.g.,</i> '<span class='user'>" + circuitQuestions[r.nextInt(circuitQuestions.length)] + "</span>'<br>\n" +
|
||||||
|
// "</ul><br>\n" +
|
||||||
|
"<br>\n" +
|
||||||
|
"<div class='assistant'>Feel free to ask your own question or use one of these examples to get started!</div><br>\n";
|
||||||
|
|
||||||
|
if (!CloudPresenter.Instance.isLoggedIn()) {
|
||||||
|
chatHtml = chatHtml + "<div class='system' id='login'>Please log into your DIYLC Cloud account in order to use the AI Assistant.</div><br>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return chatHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
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?"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.diylc.utils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class FileUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the base file name without extension from a full path.
|
||||||
|
* For example: "/path/to/myfile.diy" returns "myfile"
|
||||||
|
*/
|
||||||
|
public static String extractFileName(String path) {
|
||||||
|
if (path == null || path.isEmpty()) {
|
||||||
|
return "Untitled";
|
||||||
|
}
|
||||||
|
// Get the last part after the last separator
|
||||||
|
String fileName = path.substring(path.lastIndexOf(File.separator) + 1);
|
||||||
|
// Remove the extension if present
|
||||||
|
int dotIndex = fileName.lastIndexOf('.');
|
||||||
|
if (dotIndex > 0) {
|
||||||
|
fileName = fileName.substring(0, dotIndex);
|
||||||
|
}
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,7 +119,7 @@ public class GuitarDiagramAnalyzer extends AbstractNetlistAnalyzer implements IN
|
|||||||
return Set.of(NetlistSwitchPreference.WITH);
|
return Set.of(NetlistSwitchPreference.WITH);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException {
|
protected Summary summarize(Netlist netlist) throws TreeException {
|
||||||
List<String> notes = new ArrayList<String>();
|
List<String> notes = new ArrayList<String>();
|
||||||
|
|
||||||
Tree tree = constructTree(netlist);
|
Tree tree = constructTree(netlist);
|
||||||
@@ -128,6 +128,28 @@ public class GuitarDiagramAnalyzer extends AbstractNetlistAnalyzer implements IN
|
|||||||
return new Summary(netlist, "No pickups are connected to the output jack");
|
return new Summary(netlist, "No pickups are connected to the output jack");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processTree(tree, notes);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
String asciiTree = tree.toAsciiString();
|
||||||
|
|
||||||
|
sb.append("<br><br>")
|
||||||
|
.append("<font face='Courier New'>")
|
||||||
|
.append(asciiTree)
|
||||||
|
.append("</font>");
|
||||||
|
if (!notes.isEmpty()) {
|
||||||
|
Collections.sort(notes);
|
||||||
|
sb.append("<br><br>");
|
||||||
|
for (String v : notes) {
|
||||||
|
sb.append(v).append("<br>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Summary(netlist, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processTree(Tree tree, List<String> notes) {
|
||||||
Tree pickupTree = tree.filter(PICKUP_TYPES);
|
Tree pickupTree = tree.filter(PICKUP_TYPES);
|
||||||
|
|
||||||
if (pickupTree == null || pickupTree.getChildren().isEmpty()) {
|
if (pickupTree == null || pickupTree.getChildren().isEmpty()) {
|
||||||
@@ -242,165 +264,177 @@ public class GuitarDiagramAnalyzer extends AbstractNetlistAnalyzer implements IN
|
|||||||
|
|
||||||
Set<IDIYComponent<?>> pots = tree.extractComponents(POT_TYPES);
|
Set<IDIYComponent<?>> pots = tree.extractComponents(POT_TYPES);
|
||||||
for (IDIYComponent<?> pot : pots) {
|
for (IDIYComponent<?> pot : pots) {
|
||||||
TreeLeaf leaf1 = new TreeLeaf(pot, 0, 1);
|
processPotentiometer(pot, tree, pickupRoots, tonePotPickupReverseMap, tonePotPickupMap,
|
||||||
TreeLeaf leaf2 = new TreeLeaf(pot, 1, 2);
|
volPotTrebleBleedMap, volPotPickupMap, volPotPickupReverseMap);
|
||||||
Tree tree1 = tree.locate(leaf1, false);
|
|
||||||
Tree tree2 = tree.locate(leaf2, false);
|
|
||||||
|
|
||||||
if ((tree1 == null && tree2 != null) || (tree1 != null && tree2 == null)) {
|
|
||||||
boolean tonePotReversed = tree1 != null;
|
|
||||||
Tree t = tree1 == null ? tree2 : tree1;
|
|
||||||
Tree p = tree.findParent(t);
|
|
||||||
if (p != null && p.getChildren().size() == 2) {
|
|
||||||
Set<IDIYComponent<?>> caps = p.extractComponents(CAP_TYPES);
|
|
||||||
if (caps != null && caps.size() == 1) {
|
|
||||||
for (Map.Entry<IDIYComponent<?>, Tree> r : pickupRoots.entrySet()) {
|
|
||||||
Tree toneParent = tree.findCommonParent(p, r.getValue());
|
|
||||||
if (toneParent != null
|
|
||||||
&& toneParent.getConnectionType() == TreeConnectionType.Parallel) {
|
|
||||||
if (tonePotReversed) {
|
|
||||||
List<IDIYComponent<?>> pickupList = tonePotPickupReverseMap.get(pot);
|
|
||||||
if (pickupList == null) {
|
|
||||||
pickupList = new ArrayList<IDIYComponent<?>>();
|
|
||||||
tonePotPickupReverseMap.put(pot, pickupList);
|
|
||||||
}
|
|
||||||
pickupList.add(r.getKey());
|
|
||||||
} else {
|
|
||||||
List<IDIYComponent<?>> pickupList = tonePotPickupMap.get(pot);
|
|
||||||
if (pickupList == null) {
|
|
||||||
pickupList = new ArrayList<IDIYComponent<?>>();
|
|
||||||
tonePotPickupMap.put(pot, pickupList);
|
|
||||||
}
|
|
||||||
pickupList.add(r.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// volume
|
|
||||||
if (tree1 == null || tree2 == null)
|
|
||||||
continue;
|
|
||||||
for (Map.Entry<IDIYComponent<?>, Tree> r : pickupRoots.entrySet()) {
|
|
||||||
Tree commonParent1 = tree.findCommonParent(tree1, r.getValue());
|
|
||||||
Tree commonParent2 = tree.findCommonParent(tree2, r.getValue());
|
|
||||||
locateTrebleBleed(tree, volPotTrebleBleedMap, pot, tree1);
|
|
||||||
|
|
||||||
if (commonParent1 != null && commonParent2 != null
|
|
||||||
&& commonParent1.getConnectionType() == TreeConnectionType.Series
|
|
||||||
&& commonParent2.getConnectionType() == TreeConnectionType.Parallel) {
|
|
||||||
List<IDIYComponent<?>> pickupList = volPotPickupMap.get(pot);
|
|
||||||
if (pickupList == null) {
|
|
||||||
pickupList = new ArrayList<IDIYComponent<?>>();
|
|
||||||
volPotPickupMap.put(pot, pickupList);
|
|
||||||
}
|
|
||||||
pickupList.add(r.getKey());
|
|
||||||
} else if (commonParent1 != null && commonParent2 != null
|
|
||||||
&& commonParent1.getConnectionType() == TreeConnectionType.Parallel
|
|
||||||
&& commonParent2.getConnectionType() == TreeConnectionType.Series) {
|
|
||||||
List<IDIYComponent<?>> pickupList = volPotPickupReverseMap.get(pot);
|
|
||||||
if (pickupList == null) {
|
|
||||||
pickupList = new ArrayList<IDIYComponent<?>>();
|
|
||||||
volPotPickupReverseMap.put(pot, pickupList);
|
|
||||||
}
|
|
||||||
pickupList.add(r.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e : volPotPickupMap.entrySet()) {
|
for (Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e : volPotPickupMap.entrySet()) {
|
||||||
StringBuilder sb = new StringBuilder(
|
outputVolumePotentiometer(e, notes, volPotTrebleBleedMap);
|
||||||
"'" + e.getKey().getName() + "' potentiometer acts as a volume control for ");
|
|
||||||
boolean first = true;
|
|
||||||
List<String> pickupNames =
|
|
||||||
e.getValue().stream().map(x -> x.getName()).sorted().collect(Collectors.toList());
|
|
||||||
for (String pickupName : pickupNames) {
|
|
||||||
if (!first)
|
|
||||||
sb.append(pickupNames.size() == 2 ? " and " : ", ");
|
|
||||||
first = false;
|
|
||||||
sb.append("'").append(pickupName).append("'");
|
|
||||||
}
|
|
||||||
notes.add(sb.toString());
|
|
||||||
|
|
||||||
Set<IDIYComponent<?>> trebleBleedComponents = volPotTrebleBleedMap.get(e.getKey());
|
|
||||||
if (trebleBleedComponents != null && trebleBleedComponents.size() > 0) {
|
|
||||||
|
|
||||||
String trebleBleadNote = trebleBleedComponents.stream()
|
|
||||||
.sorted(Comparator.comparing(c -> c.getName()))
|
|
||||||
.map(c -> "'" + c.getName() + "'")
|
|
||||||
.collect(Collectors.joining(", ")) + " form a treble bleed network on the '" + e.getKey().getName() + "' volume control";
|
|
||||||
notes.add(trebleBleadNote);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e : volPotPickupReverseMap
|
for (Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e : volPotPickupReverseMap
|
||||||
.entrySet()) {
|
.entrySet()) {
|
||||||
StringBuilder sb = new StringBuilder(
|
outputVolumePotReversed(e, notes);
|
||||||
"'" + e.getKey().getName() + "' potentiometer acts as a volume control for ");
|
|
||||||
boolean first = true;
|
|
||||||
List<String> pickupNames =
|
|
||||||
e.getValue().stream().map(x -> x.getName()).sorted().collect(Collectors.toList());
|
|
||||||
for (String pickupName : pickupNames) {
|
|
||||||
if (!first)
|
|
||||||
sb.append(pickupNames.size() == 2 ? " and " : ", ");
|
|
||||||
first = false;
|
|
||||||
sb.append("'").append(pickupName).append("'");
|
|
||||||
}
|
|
||||||
sb.append(", but is wired in REVERSE!");
|
|
||||||
notes.add(sb.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e : tonePotPickupMap.entrySet()) {
|
for (Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e : tonePotPickupMap.entrySet()) {
|
||||||
StringBuilder sb = new StringBuilder(
|
outputTonePotentiometer(e, notes);
|
||||||
"'" + e.getKey().getName() + "' potentiometer acts as a tone control for ");
|
|
||||||
boolean first = true;
|
|
||||||
List<String> pickupNames =
|
|
||||||
e.getValue().stream().map(x -> x.getName()).sorted().collect(Collectors.toList());
|
|
||||||
for (String pickupName : pickupNames) {
|
|
||||||
if (!first)
|
|
||||||
sb.append(pickupNames.size() == 2 ? " and " : ", ");
|
|
||||||
first = false;
|
|
||||||
sb.append("'").append(pickupName).append("'");
|
|
||||||
}
|
|
||||||
notes.add(sb.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e : tonePotPickupReverseMap
|
for (Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e : tonePotPickupReverseMap
|
||||||
.entrySet()) {
|
.entrySet()) {
|
||||||
StringBuilder sb = new StringBuilder(
|
outputTonePotentiometerReversed(e, notes);
|
||||||
"'" + e.getKey().getName() + "' potentiometer acts as a tone control for ");
|
}
|
||||||
boolean first = true;
|
}
|
||||||
List<String> pickupNames =
|
}
|
||||||
e.getValue().stream().map(x -> x.getName()).sorted().collect(Collectors.toList());
|
|
||||||
for (String pickupName : pickupNames) {
|
private static void outputTonePotentiometerReversed(Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e,
|
||||||
if (!first)
|
List<String> notes) {
|
||||||
sb.append(pickupNames.size() == 2 ? " and " : ", ");
|
StringBuilder sb = new StringBuilder(
|
||||||
first = false;
|
"'" + e.getKey().getName() + "' potentiometer acts as a tone control for ");
|
||||||
sb.append("'").append(pickupName).append("'");
|
boolean first = true;
|
||||||
|
List<String> pickupNames =
|
||||||
|
e.getValue().stream().map(x -> x.getName()).sorted().collect(Collectors.toList());
|
||||||
|
for (String pickupName : pickupNames) {
|
||||||
|
if (!first)
|
||||||
|
sb.append(pickupNames.size() == 2 ? " and " : ", ");
|
||||||
|
first = false;
|
||||||
|
sb.append("'").append(pickupName).append("'");
|
||||||
|
}
|
||||||
|
sb.append(", but is wired in REVERSE!");
|
||||||
|
notes.add(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void outputTonePotentiometer(Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e,
|
||||||
|
List<String> notes) {
|
||||||
|
StringBuilder sb = new StringBuilder(
|
||||||
|
"'" + e.getKey().getName() + "' potentiometer acts as a tone control for ");
|
||||||
|
boolean first = true;
|
||||||
|
List<String> pickupNames =
|
||||||
|
e.getValue().stream().map(x -> x.getName()).sorted().collect(Collectors.toList());
|
||||||
|
for (String pickupName : pickupNames) {
|
||||||
|
if (!first)
|
||||||
|
sb.append(pickupNames.size() == 2 ? " and " : ", ");
|
||||||
|
first = false;
|
||||||
|
sb.append("'").append(pickupName).append("'");
|
||||||
|
}
|
||||||
|
notes.add(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void outputVolumePotReversed(Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e,
|
||||||
|
List<String> notes) {
|
||||||
|
StringBuilder sb = new StringBuilder(
|
||||||
|
"'" + e.getKey().getName() + "' potentiometer acts as a volume control for ");
|
||||||
|
boolean first = true;
|
||||||
|
List<String> pickupNames =
|
||||||
|
e.getValue().stream().map(x -> x.getName()).sorted().collect(Collectors.toList());
|
||||||
|
for (String pickupName : pickupNames) {
|
||||||
|
if (!first)
|
||||||
|
sb.append(pickupNames.size() == 2 ? " and " : ", ");
|
||||||
|
first = false;
|
||||||
|
sb.append("'").append(pickupName).append("'");
|
||||||
|
}
|
||||||
|
sb.append(", but is wired in REVERSE!");
|
||||||
|
notes.add(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void outputVolumePotentiometer(Map.Entry<IDIYComponent<?>, List<IDIYComponent<?>>> e,
|
||||||
|
List<String> notes, Map<IDIYComponent<?>, Set<IDIYComponent<?>>> volPotTrebleBleedMap) {
|
||||||
|
StringBuilder sb = new StringBuilder(
|
||||||
|
"'" + e.getKey().getName() + "' potentiometer acts as a volume control for ");
|
||||||
|
boolean first = true;
|
||||||
|
List<String> pickupNames =
|
||||||
|
e.getValue().stream().map(x -> x.getName()).sorted().collect(Collectors.toList());
|
||||||
|
for (String pickupName : pickupNames) {
|
||||||
|
if (!first)
|
||||||
|
sb.append(pickupNames.size() == 2 ? " and " : ", ");
|
||||||
|
first = false;
|
||||||
|
sb.append("'").append(pickupName).append("'");
|
||||||
|
}
|
||||||
|
notes.add(sb.toString());
|
||||||
|
|
||||||
|
Set<IDIYComponent<?>> trebleBleedComponents = volPotTrebleBleedMap.get(e.getKey());
|
||||||
|
if (trebleBleedComponents != null && trebleBleedComponents.size() > 0) {
|
||||||
|
|
||||||
|
String trebleBleadNote = trebleBleedComponents.stream()
|
||||||
|
.sorted(Comparator.comparing(c -> c.getName()))
|
||||||
|
.map(c -> "'" + c.getName() + "'")
|
||||||
|
.collect(Collectors.joining(", ")) + " form a treble bleed network on the '" + e.getKey().getName() + "' volume control";
|
||||||
|
notes.add(trebleBleadNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPotentiometer(IDIYComponent<?> pot, Tree tree, Map<IDIYComponent<?>, Tree> pickupRoots,
|
||||||
|
Map<IDIYComponent<?>, List<IDIYComponent<?>>> tonePotPickupReverseMap,
|
||||||
|
Map<IDIYComponent<?>, List<IDIYComponent<?>>> tonePotPickupMap,
|
||||||
|
Map<IDIYComponent<?>, Set<IDIYComponent<?>>> volPotTrebleBleedMap,
|
||||||
|
Map<IDIYComponent<?>, List<IDIYComponent<?>>> volPotPickupMap,
|
||||||
|
Map<IDIYComponent<?>, List<IDIYComponent<?>>> volPotPickupReverseMap) {
|
||||||
|
TreeLeaf leaf1 = new TreeLeaf(pot, 0, 1);
|
||||||
|
TreeLeaf leaf2 = new TreeLeaf(pot, 1, 2);
|
||||||
|
Tree tree1 = tree.locate(leaf1, false);
|
||||||
|
Tree tree2 = tree.locate(leaf2, false);
|
||||||
|
|
||||||
|
if ((tree1 == null && tree2 != null) || (tree1 != null && tree2 == null)) {
|
||||||
|
boolean tonePotReversed = tree1 != null;
|
||||||
|
Tree t = tree1 == null ? tree2 : tree1;
|
||||||
|
Tree p = tree.findParent(t);
|
||||||
|
if (p != null && p.getChildren().size() == 2) {
|
||||||
|
Set<IDIYComponent<?>> caps = p.extractComponents(CAP_TYPES);
|
||||||
|
if (caps != null && caps.size() == 1) {
|
||||||
|
for (Map.Entry<IDIYComponent<?>, Tree> r : pickupRoots.entrySet()) {
|
||||||
|
Tree toneParent = tree.findCommonParent(p, r.getValue());
|
||||||
|
if (toneParent != null
|
||||||
|
&& toneParent.getConnectionType() == TreeConnectionType.Parallel) {
|
||||||
|
if (tonePotReversed) {
|
||||||
|
List<IDIYComponent<?>> pickupList = tonePotPickupReverseMap.get(pot);
|
||||||
|
if (pickupList == null) {
|
||||||
|
pickupList = new ArrayList<IDIYComponent<?>>();
|
||||||
|
tonePotPickupReverseMap.put(pot, pickupList);
|
||||||
|
}
|
||||||
|
pickupList.add(r.getKey());
|
||||||
|
} else {
|
||||||
|
List<IDIYComponent<?>> pickupList = tonePotPickupMap.get(pot);
|
||||||
|
if (pickupList == null) {
|
||||||
|
pickupList = new ArrayList<IDIYComponent<?>>();
|
||||||
|
tonePotPickupMap.put(pot, pickupList);
|
||||||
|
}
|
||||||
|
pickupList.add(r.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sb.append(", but is wired in REVERSE!");
|
|
||||||
notes.add(sb.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
// volume
|
||||||
|
if (tree1 == null || tree2 == null)
|
||||||
|
return;
|
||||||
|
for (Map.Entry<IDIYComponent<?>, Tree> r : pickupRoots.entrySet()) {
|
||||||
|
Tree commonParent1 = tree.findCommonParent(tree1, r.getValue());
|
||||||
|
Tree commonParent2 = tree.findCommonParent(tree2, r.getValue());
|
||||||
|
locateTrebleBleed(tree, volPotTrebleBleedMap, pot, tree1);
|
||||||
|
|
||||||
String asciiTree = tree.toAsciiString();
|
if (commonParent1 != null && commonParent2 != null
|
||||||
|
&& commonParent1.getConnectionType() == TreeConnectionType.Series
|
||||||
sb.append("<br><br>")
|
&& commonParent2.getConnectionType() == TreeConnectionType.Parallel) {
|
||||||
.append("<font face='Courier New'>")
|
List<IDIYComponent<?>> pickupList = volPotPickupMap.get(pot);
|
||||||
.append(asciiTree)
|
if (pickupList == null) {
|
||||||
.append("</font>");
|
pickupList = new ArrayList<IDIYComponent<?>>();
|
||||||
if (!notes.isEmpty()) {
|
volPotPickupMap.put(pot, pickupList);
|
||||||
Collections.sort(notes);
|
}
|
||||||
sb.append("<br><br>");
|
pickupList.add(r.getKey());
|
||||||
for (String v : notes) {
|
} else if (commonParent1 != null && commonParent2 != null
|
||||||
sb.append(v).append("<br>");
|
&& commonParent1.getConnectionType() == TreeConnectionType.Parallel
|
||||||
|
&& commonParent2.getConnectionType() == TreeConnectionType.Series) {
|
||||||
|
List<IDIYComponent<?>> pickupList = volPotPickupReverseMap.get(pot);
|
||||||
|
if (pickupList == null) {
|
||||||
|
pickupList = new ArrayList<IDIYComponent<?>>();
|
||||||
|
volPotPickupReverseMap.put(pot, pickupList);
|
||||||
|
}
|
||||||
|
pickupList.add(r.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Summary(netlist, sb.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void locateTrebleBleed(Tree tree,
|
private void locateTrebleBleed(Tree tree,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class MultimeterAnalyzer extends AbstractNetlistAnalyzer implements INetl
|
|||||||
return EnumSet.allOf(NetlistSwitchPreference.class);
|
return EnumSet.allOf(NetlistSwitchPreference.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException {
|
protected Summary summarize(Netlist netlist) throws TreeException {
|
||||||
Tree tree = constructTree(netlist);
|
Tree tree = constructTree(netlist);
|
||||||
|
|
||||||
if (tree == null) {
|
if (tree == null) {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class SpiceAnalyzer extends AbstractNetlistAnalyzer implements INetlistAn
|
|||||||
return EnumSet.allOf(NetlistSwitchPreference.class);
|
return EnumSet.allOf(NetlistSwitchPreference.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException {
|
protected Summary summarize(Netlist netlist) throws TreeException {
|
||||||
// grab all components that are in the netlist
|
// grab all components that are in the netlist
|
||||||
List<Group> groups = netlist.getSortedGroups();
|
List<Group> groups = netlist.getSortedGroups();
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ public class SummarizeNetlistAction extends AbstractAction {
|
|||||||
throw new Exception("The generated netlist is empty, nothing to show.");
|
throw new Exception("The generated netlist is empty, nothing to show.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return summarizer.summarize(netlists, null);
|
return summarizer.summarize(netlists);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,93 +18,6 @@ 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);
|
||||||
@@ -113,10 +26,9 @@ public class ChatbotPane extends JPanel {
|
|||||||
|
|
||||||
private ISwingUI swingUI;
|
private ISwingUI swingUI;
|
||||||
private IPlugInPort plugInPort;
|
private IPlugInPort plugInPort;
|
||||||
|
private ChatbotPresenter chatbotPresenter;
|
||||||
|
|
||||||
private JLabel titleLabel;
|
|
||||||
private JTextArea promptArea;
|
private JTextArea promptArea;
|
||||||
private JScrollPane chatScrollPane;
|
|
||||||
private JEditorPane chatEditorPane;
|
private JEditorPane chatEditorPane;
|
||||||
private JButton askButton;
|
private JButton askButton;
|
||||||
private JButton clearButton;
|
private JButton clearButton;
|
||||||
@@ -125,6 +37,7 @@ public class ChatbotPane extends JPanel {
|
|||||||
super();
|
super();
|
||||||
this.swingUI = swingUI;
|
this.swingUI = swingUI;
|
||||||
this.plugInPort = plugInPort;
|
this.plugInPort = plugInPort;
|
||||||
|
this.chatbotPresenter = new ChatbotPresenter(plugInPort);
|
||||||
setName("AI Assistant");
|
setName("AI Assistant");
|
||||||
|
|
||||||
// Set panel background color
|
// Set panel background color
|
||||||
@@ -148,17 +61,6 @@ public class ChatbotPane extends JPanel {
|
|||||||
gbc.gridwidth = 2; // Span both columns
|
gbc.gridwidth = 2; // Span both columns
|
||||||
add(chatScrollPane, gbc);
|
add(chatScrollPane, gbc);
|
||||||
|
|
||||||
// Prompt label
|
|
||||||
JLabel promptLabel = new JLabel("Prompt:");
|
|
||||||
promptLabel.setForeground(TERMINAL_FG);
|
|
||||||
promptLabel.setFont(DEFAULT_FONT);
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy = 2;
|
|
||||||
gbc.weightx = 0.0;
|
|
||||||
gbc.weighty = 0.0;
|
|
||||||
gbc.gridwidth = 1;
|
|
||||||
// add(promptLabel, gbc);
|
|
||||||
|
|
||||||
// Prompt scroll pane
|
// Prompt scroll pane
|
||||||
JScrollPane promptScrollPane = new JScrollPane(getPromptArea(),
|
JScrollPane promptScrollPane = new JScrollPane(getPromptArea(),
|
||||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||||
@@ -310,7 +212,7 @@ public class ChatbotPane extends JPanel {
|
|||||||
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());
|
||||||
|
|
||||||
String sampleChat = getInitialChatContents();
|
String sampleChat = chatbotPresenter.getInitialChatContents();
|
||||||
|
|
||||||
chatEditorPane.setContentType("text/html");
|
chatEditorPane.setContentType("text/html");
|
||||||
chatEditorPane.setText(htmlStyle + "<body><pre>" + sampleChat + "</pre></body>");
|
chatEditorPane.setText(htmlStyle + "<body><pre>" + sampleChat + "</pre></body>");
|
||||||
@@ -318,29 +220,6 @@ public class ChatbotPane extends JPanel {
|
|||||||
return chatEditorPane;
|
return chatEditorPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getInitialChatContents() {
|
|
||||||
Random r = new Random();
|
|
||||||
|
|
||||||
String chatHtml =
|
|
||||||
"<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" +
|
|
||||||
"\n" +
|
|
||||||
"- <b>Electronics theory or concepts:</b> <i>e.g.,</i> '<span class='user'>" + electronicsQuestions[r.nextInt(
|
|
||||||
electronicsQuestions.length)] + "</span>'<br>\n" +
|
|
||||||
"- <b>DIYLC features and usage:</b> <i>e.g.,</i> '<span class='user'>" + diylcQuestions[r.nextInt(diylcQuestions.length)] + "</span>'<br>\n" +
|
|
||||||
"- <b>Your current circuit project:</b> <i>e.g.,</i> '<span class='user'>" + circuitQuestions[r.nextInt(circuitQuestions.length)] + "</span>'<br>\n" +
|
|
||||||
// "</ul><br>\n" +
|
|
||||||
"<br>\n" +
|
|
||||||
"<div class='assistant'>Feel free to ask your own question or use one of these examples to get started!</div><br>\n";
|
|
||||||
|
|
||||||
if (!CloudPresenter.Instance.isLoggedIn()) {
|
|
||||||
chatHtml = chatHtml + "<div class='system' id='login'>Please log into your DIYLC Cloud account in order to use the AI Assistant.</div><br>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return chatHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JButton getAskButton() {
|
public JButton getAskButton() {
|
||||||
if (askButton == null) {
|
if (askButton == null) {
|
||||||
askButton = new JButton("Ask");
|
askButton = new JButton("Ask");
|
||||||
@@ -350,11 +229,10 @@ 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(ChatbotPresenter.USER, prompt);
|
||||||
appendSection(TEMPORARY, "Waiting for the response...");
|
appendSection(ChatbotPresenter.TEMPORARY, "Waiting for the response...");
|
||||||
getPromptArea().setText(null);
|
getPromptArea().setText(null);
|
||||||
String currentFile = plugInPort.getCurrentFileName();
|
|
||||||
String fileName = extractFileName(currentFile);
|
|
||||||
|
|
||||||
getAskButton().setEnabled(false);
|
getAskButton().setEnabled(false);
|
||||||
getClearButton().setEnabled(false);
|
getClearButton().setEnabled(false);
|
||||||
@@ -362,19 +240,19 @@ public class ChatbotPane extends JPanel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String doInBackground() throws Exception {
|
public String doInBackground() throws Exception {
|
||||||
return ChatbotPresenter.Instance.promptChatbot(fileName, "", prompt);
|
return chatbotPresenter.promptChatbot(prompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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(ChatbotPresenter.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(ChatbotPresenter.ASSISTANT, result);
|
||||||
getClearButton().setEnabled(true);
|
getClearButton().setEnabled(true);
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
@@ -396,24 +274,6 @@ public class ChatbotPane extends JPanel {
|
|||||||
getChatEditorPane().setText(text);
|
getChatEditorPane().setText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the base file name without extension from a full path.
|
|
||||||
* For example: "/path/to/myfile.diy" returns "myfile"
|
|
||||||
*/
|
|
||||||
private String extractFileName(String path) {
|
|
||||||
if (path == null || path.isEmpty()) {
|
|
||||||
return "Untitled";
|
|
||||||
}
|
|
||||||
// Get the last part after the last separator
|
|
||||||
String fileName = path.substring(path.lastIndexOf(File.separator) + 1);
|
|
||||||
// Remove the extension if present
|
|
||||||
int dotIndex = fileName.lastIndexOf('.');
|
|
||||||
if (dotIndex > 0) {
|
|
||||||
fileName = fileName.substring(0, dotIndex);
|
|
||||||
}
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JButton getClearButton() {
|
public JButton getClearButton() {
|
||||||
if (clearButton == null) {
|
if (clearButton == null) {
|
||||||
clearButton = new JButton("Clear");
|
clearButton = new JButton("Clear");
|
||||||
|
|||||||
Reference in New Issue
Block a user