mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-07 12:24:58 +10:00
chatbot enhancements
This commit is contained in:
@@ -20,4 +20,15 @@
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
<filteredResources>
|
||||
<filter>
|
||||
<id>1743865242662</id>
|
||||
<name></name>
|
||||
<type>30</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
</filteredResources>
|
||||
</projectDescription>
|
||||
|
||||
@@ -23,6 +23,7 @@ package org.diylc.plugins.chatbot.model;
|
||||
|
||||
import com.diyfever.httpproxy.ParamName;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public interface IChatbotAPI {
|
||||
@@ -40,7 +41,7 @@ public interface IChatbotAPI {
|
||||
*/
|
||||
String promptChatbot(@ParamName("username") String username, @ParamName("token") String token,
|
||||
@ParamName("machineId") String machineId, @ParamName("project") String project,
|
||||
@ParamName("netlist") String netlist, @ParamName("prompt") String prompt);
|
||||
@ParamName("netlist") File netlist, @ParamName("prompt") String prompt);
|
||||
|
||||
SubscriptionEntity getSubscriptionInfo(@ParamName("username") String username, @ParamName("token") String token,
|
||||
@ParamName("machineId") String machineId);
|
||||
|
||||
+69
-19
@@ -30,6 +30,7 @@ import org.diylc.common.ComponentType;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.ISwitch;
|
||||
import org.diylc.netlist.Group;
|
||||
import org.diylc.netlist.Netlist;
|
||||
import org.diylc.netlist.NetlistException;
|
||||
@@ -43,6 +44,9 @@ import org.diylc.presenter.ComponentProcessor;
|
||||
import org.diylc.utils.FileUtils;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -89,17 +93,36 @@ public class ChatbotService {
|
||||
String fileName = extractFileName(currentFile);
|
||||
|
||||
String netlist;
|
||||
File netlistFile = null;
|
||||
try {
|
||||
netlist = extractNetlists();
|
||||
} catch (NetlistException e) {
|
||||
LOG.error("Error extracting netlist", e);
|
||||
if (netlist != null) {
|
||||
netlistFile = File.createTempFile("diylc_netlist_", ".txt");
|
||||
try (FileWriter writer = new FileWriter(netlistFile)) {
|
||||
writer.write(netlist);
|
||||
}
|
||||
// Make sure the temp file is deleted when the JVM exits
|
||||
netlistFile.deleteOnExit();
|
||||
}
|
||||
} catch (NetlistException | IOException e) {
|
||||
LOG.error("Error extracting or saving netlist", e);
|
||||
netlist = null;
|
||||
}
|
||||
|
||||
return getService().promptChatbot(
|
||||
plugInPort.getCloudService().getCurrentUsername(),
|
||||
plugInPort.getCloudService().getCurrentToken(),
|
||||
plugInPort.getCloudService().getMachineId(), fileName, netlist, prompt);
|
||||
try {
|
||||
return getService().promptChatbot(
|
||||
plugInPort.getCloudService().getCurrentUsername(),
|
||||
plugInPort.getCloudService().getCurrentToken(),
|
||||
plugInPort.getCloudService().getMachineId(),
|
||||
fileName,
|
||||
netlistFile,
|
||||
prompt);
|
||||
} finally {
|
||||
// Clean up the temp file immediately after use
|
||||
if (netlistFile != null && netlistFile.exists()) {
|
||||
netlistFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Set<Class<?>> PROPERTY_TYPES_TO_SKIP = Set.of(Font.class, Color.class);
|
||||
@@ -108,12 +131,11 @@ public class ChatbotService {
|
||||
private String extractNetlists() throws NetlistException {
|
||||
List<Netlist> netlists = plugInPort.extractNetlists(true);
|
||||
|
||||
if (netlists == null) {
|
||||
if (netlists == null || netlists.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Components: ");
|
||||
|
||||
Set<? extends IDIYComponent<?>> components = netlists.stream()
|
||||
.flatMap(n -> n.getGroups().stream()
|
||||
@@ -121,8 +143,45 @@ public class ChatbotService {
|
||||
map(Node::getComponent)))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (!components.isEmpty()) {
|
||||
sb.append(
|
||||
"Components (each element of the JSON array represents one component with all the relevant properties): ");
|
||||
outputComponents(components, sb);
|
||||
}
|
||||
|
||||
Set<? extends IDIYComponent<?>> switches = plugInPort.getCurrentProject().getComponents()
|
||||
.stream().filter(x -> x instanceof ISwitch)
|
||||
.collect(Collectors.toSet());;
|
||||
|
||||
if (!switches.isEmpty()) {
|
||||
sb.append(
|
||||
"Switches (each element of the JSON array represents one switch with all the relevant properties): ");
|
||||
outputComponents(switches, sb);
|
||||
}
|
||||
|
||||
for (Netlist netlist : netlists) {
|
||||
sb.append("\n");
|
||||
if (!netlist.getSwitchSetup().isEmpty()) {
|
||||
sb.append("Switch configuration: ").append(netlist.getSwitchSetup()).append(". ");
|
||||
}
|
||||
sb.append("Each line below represents one JSON array that lists all the nodes that are connected together. Nodes are labeled as (component name).(node name):\n\n");
|
||||
for (Group v : netlist.getSortedGroups()) {
|
||||
// sb.append(v.getSortedNodes()).append("\n");
|
||||
List<String> nodeList = v.getSortedNodes().stream().map(x -> x.getComponent().getName() + "." + x.getDisplayName()).toList();
|
||||
try {
|
||||
String json = MAPPER.writeValueAsString(nodeList);
|
||||
sb.append(json).append("\n");
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to serialize component descriptors to JSON", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void outputComponents(Set<? extends IDIYComponent<?>> components, StringBuilder sb) {
|
||||
List<Map<String, Object>> componentDescriptors = new ArrayList<>();
|
||||
|
||||
|
||||
components.forEach(c -> {
|
||||
ComponentType componentType = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||
@@ -148,7 +207,7 @@ public class ChatbotService {
|
||||
LOG.warn("Error extracting properties", e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
componentDescriptors.add(componentDescriptorMap);
|
||||
});
|
||||
|
||||
@@ -158,15 +217,6 @@ public class ChatbotService {
|
||||
} 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 SubscriptionEntity getSubscriptionInfo() throws NotLoggedInException {
|
||||
|
||||
@@ -21,7 +21,9 @@ public class ChatbotPane extends JPanel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(ChatbotPane.class);
|
||||
|
||||
public static final String ME = "Me: ";
|
||||
public static final String AI_ASSISTANT = "AI Assistant: ";
|
||||
|
||||
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 Color TERMINAL_BG = new Color(40, 40, 40);
|
||||
@@ -45,7 +47,7 @@ public class ChatbotPane extends JPanel {
|
||||
private JButton clearButton;
|
||||
|
||||
private boolean loggedIn = false;
|
||||
private String projectFileName = "initial";
|
||||
private String projectFileName = null;
|
||||
|
||||
public ChatbotPane(ISwingUI swingUI, IPlugInPort plugInPort) {
|
||||
super();
|
||||
@@ -221,8 +223,8 @@ public class ChatbotPane extends JPanel {
|
||||
try {
|
||||
SubscriptionEntity subscriptionInfo = plugInPort.getChatbotService().getSubscriptionInfo();
|
||||
appendSection(ChatbotService.SYSTEM,
|
||||
"Your current subscription tier is " + subscriptionInfo.getTier() +
|
||||
" expiring on " + subscriptionInfo.getEndDate() + " with " +
|
||||
"Your are currently subscribed to the '" + subscriptionInfo.getTier() +
|
||||
"' tier, expiring on " + subscriptionInfo.getEndDate() + ", with " +
|
||||
subscriptionInfo.getRemainingCredits() + " credits remaining.");
|
||||
} catch (NotLoggedInException e) {
|
||||
LOG.error("Error getting subscription info", e);
|
||||
@@ -238,8 +240,8 @@ public class ChatbotPane extends JPanel {
|
||||
try {
|
||||
List<ChatMessageEntity> chatHistory = plugInPort.getChatbotService().getChatHistory();
|
||||
chatHistory.forEach(message -> {
|
||||
appendSection(ChatbotService.USER, message.getPrompt());
|
||||
appendSection(ChatbotService.ASSISTANT, message.getResponse());
|
||||
appendSection(ChatbotService.USER, ME + message.getPrompt());
|
||||
appendSection(ChatbotService.ASSISTANT, AI_ASSISTANT + message.getResponse());
|
||||
});
|
||||
} catch (NotLoggedInException e) {
|
||||
appendSection(ChatbotService.SYSTEM, "Failed to retrieve chat history.");
|
||||
@@ -257,6 +259,8 @@ public class ChatbotPane extends JPanel {
|
||||
|
||||
chatEditorPane.setContentType("text/html");
|
||||
chatEditorPane.setText(HTML_STYLE + "<body></body>");
|
||||
|
||||
refreshChat();
|
||||
}
|
||||
return chatEditorPane;
|
||||
}
|
||||
@@ -296,7 +300,7 @@ public class ChatbotPane extends JPanel {
|
||||
askButton.setBorderPainted(true);
|
||||
askButton.addActionListener(e -> {
|
||||
final String prompt = getPromptArea().getText();
|
||||
appendSection(ChatbotService.USER, prompt);
|
||||
appendSection(ChatbotService.USER, ME + prompt);
|
||||
appendSection(ChatbotService.TEMPORARY, "Waiting for the response...");
|
||||
getPromptArea().setText(null);
|
||||
|
||||
@@ -319,7 +323,7 @@ public class ChatbotPane extends JPanel {
|
||||
|
||||
@Override
|
||||
public void complete(String result) {
|
||||
appendSection(ChatbotService.ASSISTANT, result);
|
||||
appendSection(ChatbotService.ASSISTANT, AI_ASSISTANT + result);
|
||||
getClearButton().setEnabled(true);
|
||||
}
|
||||
}, false);
|
||||
@@ -328,7 +332,7 @@ public class ChatbotPane extends JPanel {
|
||||
return askButton;
|
||||
}
|
||||
|
||||
void appendSection(String style, String insertText) {
|
||||
private void appendSection(String style, String insertText) {
|
||||
String text = getChatEditorPane().getText();
|
||||
// remove any temporary divs
|
||||
String regex = "(?s)<div\\s+class=[\"']temporary[\"'][^>]*>.*?</div>\\s*<br>\\s*";
|
||||
|
||||
@@ -219,4 +219,29 @@ INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manua
|
||||
* Solid Java knowledge (including generics, annotations, and familiarity with **Graphics2D** for rendering).
|
||||
* Docker (only for building the deployment packages)
|
||||
|
||||
Note: Unlike DIYLC v2, versions 3 and higher components require actual Java coding for custom appearance and behavior. This raises the bar for non-programmers but gives greater flexibility and performance.');
|
||||
Note: Unlike DIYLC v2, versions 3 and higher components require actual Java coding for custom appearance and behavior. This raises the bar for non-programmers but gives greater flexibility and performance.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'DIYLC Cloud';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'DIYLC Cloud',
|
||||
'The DIYLC Cloud feature connects users to a central hub and offers several powerful capabilities:
|
||||
- Upload and Share Projects: Save your DIYLC projects online and share them with the community.
|
||||
- Search and Download Projects: Access a library of existing projects uploaded by other users.
|
||||
- Access AI Assistant: Use the AI Assistant to get help with using the app, designing circuits, and troubleshooting projects.
|
||||
The Cloud feature is open to all users but requires creating an account with a valid email address. Your email is used only for login purposes and will never be shared or used for any other reason.
|
||||
The only way to create and access a DIYLC Cloud account is through the "Cloud" tab in the main menu of the DIYLC application.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'AI Assistant';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'AI Assitant/Chatbot/ChatGPT/GPT',
|
||||
'DIYLC AI Assistant is an integrated feature that allows users to interact with DIY Layout Creator (DIYLC) using natural language. It functions as a chatbot powered by the OpenAI API to generate helpful responses. The AI Assistant is available only while logged into the DIYLC Cloud with an active account and requires an internet connection.
|
||||
There are two subscription tiers for using the AI Assistant:
|
||||
- Free Tier: Provides limited monthly usage and access to basic AI models. This option is automatically available to all registered DIYLC Cloud users.
|
||||
-Premium Tier: Offers up to 1000 requests per month using more advanced AI models. The Premium subscription is exclusively available to Patreon supporters with the "Premium AI" tier.
|
||||
');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'AI Assistant - Using the AI Assistant';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'AI Assitant/Chatbot/ChatGPT/GPT - Using the AI Assistant',
|
||||
'DIYLC AI Assistant can assist users with a wide variety of tasks, including:
|
||||
- General Electronics Questions: Ask about electronics theory, parts, components, guitars, and related topics.
|
||||
-Circuit Design Assistance: Describe the type of circuit you want to build, and the AI Assistant will suggest design ideas and possible circuit layouts.
|
||||
- Circuit Troubleshooting: Get help with specific questions or troubleshoot problems with your circuit. The AI Assistant can read your project file, analyze all components and connections, and provide detailed explanations of the circuit’s behavior.
|
||||
- Learning DIYLC Features: Ask questions about DIY Layout Creator (DIYLC). The AI Assistant is trained on the complete DIYLC user manual and can explain software features, tools, and workflows.');
|
||||
Reference in New Issue
Block a user