From a8f9611db405b74191ae219b9490fbb1cfcc5d1b Mon Sep 17 00:00:00 2001 From: tzdwindows 7 <3076584115@qq.com> Date: Mon, 10 Feb 2025 13:30:38 +0800 Subject: [PATCH] =?UTF-8?q?feat(core):=20=E5=AE=9E=E7=8E=B0=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E5=8A=A0=E8=BD=BD=E7=B3=BB=E7=BB=9F=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=97=A5=E5=BF=97=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增插件加载系统,支持从指定目录加载插件 - 引入log4j2日志框架,优化日志记录和管理 - 重构主程序启动逻辑,增加加载动画和系统信息输出 - 优化窗口样式和布局,提高用户体验 --- build.gradle | 10 + .../java/com/axis/innovators/box/Main.java | 177 +++++++++++++----- .../axis/innovators/box/gui/FridaWindow.java | 68 +++---- .../com/axis/innovators/box/gui/LoadIcon.java | 5 + .../axis/innovators/box/gui/LocalWindow.java | 67 ++++--- .../axis/innovators/box/gui/MainWindow.java | 103 +--------- .../box/plugins/PluginDescriptor.java | 29 +++ .../innovators/box/plugins/PluginLoader.java | 148 +++++++++++++++ .../innovators/box/plugins/PluginMeta.java | 20 ++ .../innovators/box/tools/FolderCreator.java | 21 ++- .../innovators/box/tools/SystemInfoUtil.java | 95 ++++++++++ src/main/java/org/tzd/lm/LM.java | 27 ++- src/main/java/org/tzd/lm/LMApi.java | 1 + src/main/resources/log4j2.xml | 45 +++++ 14 files changed, 601 insertions(+), 215 deletions(-) create mode 100644 src/main/java/com/axis/innovators/box/plugins/PluginDescriptor.java create mode 100644 src/main/java/com/axis/innovators/box/plugins/PluginLoader.java create mode 100644 src/main/java/com/axis/innovators/box/plugins/PluginMeta.java create mode 100644 src/main/java/com/axis/innovators/box/tools/SystemInfoUtil.java create mode 100644 src/main/resources/log4j2.xml diff --git a/build.gradle b/build.gradle index 3d15d65..3ad347e 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,16 @@ dependencies { implementation 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.1' // https://mvnrepository.com/artifact/com.google.code.gson/gson implementation 'com.google.code.gson:gson:2.8.9' + + implementation 'org.apache.logging.log4j:log4j-api:2.20.0' + implementation 'org.apache.logging.log4j:log4j-core:2.20.0' + implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0' + + implementation 'org.ow2.asm:asm:7.1' + implementation 'org.ow2.asm:asm-commons:7.1' + implementation 'org.ow2.asm:asm-analysis:7.1' + implementation 'org.ow2.asm:asm-util:7.0' + implementation 'org.ow2.asm:asm-tree:7.1' } application { diff --git a/src/main/java/com/axis/innovators/box/Main.java b/src/main/java/com/axis/innovators/box/Main.java index 261942c..14b27f6 100644 --- a/src/main/java/com/axis/innovators/box/Main.java +++ b/src/main/java/com/axis/innovators/box/Main.java @@ -6,8 +6,12 @@ import com.axis.innovators.box.events.SubscribeEvent; import com.axis.innovators.box.gui.FridaWindow; import com.axis.innovators.box.gui.LocalWindow; import com.axis.innovators.box.gui.MainWindow; +import com.axis.innovators.box.gui.LoadIcon; +import com.axis.innovators.box.plugins.PluginLoader; import com.axis.innovators.box.tools.LibraryLoad; -import org.markdown4j.Markdown4jProcessor; +import com.axis.innovators.box.tools.SystemInfoUtil; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import javax.swing.*; import java.awt.*; @@ -19,9 +23,23 @@ import java.io.IOException; * @author tzdwindows 7 */ public class Main { + private static final Logger logger = LogManager.getLogger(Main.class); + private static final String VERSIONS = "0.0.1"; + private static final String[] AUTHOR = new String[]{ + "tzdwindows 7" + }; + /** 我是总任务数 **/ + public static int totalTasks = 1; + /** 我是当前任务数 **/ + public static int completedTasks = 0; static { - LibraryLoad.loadLibrary("FridaNative"); + try { + LibraryLoad.loadLibrary("FridaNative"); + } catch (Exception e) { + logger.error("Failed to load the 'FridaNative' library", e); + throw new RuntimeException(e); + } } @SubscribeEvent @@ -31,60 +49,131 @@ public class Main { placeholder.setForeground(new Color(127, 140, 153)); event.content().add(placeholder, BorderLayout.CENTER); - // 我不想写这个了你们自己实现 } - public static void main(String[] args) throws IOException { + public static void main(String[] args) { + // 输出版本和作者信息 + logger.info("Application Version: {}", VERSIONS); + logger.info("Authors: {}", String.join(", ", AUTHOR)); + + // 输出系统信息 + logger.info("Operating System: {}", SystemInfoUtil.getOSName()); + logger.info("OS Architecture: {}", SystemInfoUtil.getOSArch()); + logger.info("CPU: {}", SystemInfoUtil.getCPUInfo()); + logger.info("GPU: {}", SystemInfoUtil.getGPUInfo()); + // 注册事件 GlobalEventBus.EVENT_BUS.register(new Main()); + // 设置系统外观 try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception ignored) {} + } catch (Exception e) { + logger.warn("Failed to load the system facade class", e); + } - // 创建窗口 - SwingUtilities.invokeLater(() -> { - MainWindow ex = new MainWindow(); - int id = 0; - MainWindow.ToolCategory debugCategory = new MainWindow.ToolCategory("调试工具", - "debug/debug.png", - "用于调试指定Windows工具的一个分类"); + JFrame loadingFrame = new JFrame("加载中..."); + loadingFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + loadingFrame.setSize(400, 200); + loadingFrame.setLocationRelativeTo(null); + loadingFrame.setIconImage(LoadIcon.loadIcon("logo.png", 64).getImage()); - debugCategory.addTool(new MainWindow.ToolItem("Frida注入工具", "debug/frida/frida_main.png", - "使用frida注入目标进程的脚本程序 " + - "\n作者:tzdwindows 7", ++id, new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - Window owner = SwingUtilities.windowForComponent((Component) e.getSource()); - FridaWindow fridaWindow = new FridaWindow(owner); - fridaWindow.setVisible(true); + JPanel loadingPanel = new JPanel(new BorderLayout()); + JProgressBar progressBar = new JProgressBar(0, 100); + progressBar.setStringPainted(true); + JLabel statusLabel = new JLabel("Initializing...", SwingConstants.CENTER); + JLabel timeLabel = new JLabel("Time elapsed: 0s", SwingConstants.CENTER); + JLabel logoLabel = new JLabel(LoadIcon.loadIcon("logo.png", 64)); + + loadingPanel.add(logoLabel, BorderLayout.NORTH); + loadingPanel.add(progressBar, BorderLayout.CENTER); + loadingPanel.add(statusLabel, BorderLayout.SOUTH); + loadingPanel.add(timeLabel, BorderLayout.SOUTH); + + loadingFrame.add(loadingPanel); + loadingFrame.setVisible(true); + + new Thread(() -> { + long startTime = System.currentTimeMillis(); + int classifyTask = 0; + + new Thread(() -> { + while (completedTasks < totalTasks) { + completedTasks++; + final int progress = (int) ((completedTasks / (double) totalTasks) * 100); + + SwingUtilities.invokeLater(() -> { + progressBar.setValue(progress); + statusLabel.setText("Loading: " + progress + "%"); + long elapsedTime = (System.currentTimeMillis() - startTime) / 1000; + timeLabel.setText("Time elapsed: " + elapsedTime + "s"); + }); } - })); - - // 在后面注册你自己的项或是添加你自己的分类 - // .... - - ex.addToolCategory(debugCategory); - - MainWindow.ToolCategory aICategory = new MainWindow.ToolCategory("AI工具", - "ai/ai.png", - "人工智能/大语言模型"); - - aICategory.addTool(new MainWindow.ToolItem("本地AI执行工具", "ai/local/local_main.png", - "在本机对开源大语言模型进行推理" + - "\n作者:tzdwindows 7", ++id, new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - Window owner = SwingUtilities.windowForComponent((Component) e.getSource()); - LocalWindow dialog = new LocalWindow(owner); - dialog.setVisible(true); + }); + while (completedTasks < totalTasks) { + try { + if (classifyTask == 0){ + PluginLoader.loadPlugins(); + logger.info("Loaded plugins"); + classifyTask++; + } + // 非显示任务请添加在这添加 + // .... + } catch (IOException e) { + logger.error("Failed to load plugins", e); + throw new RuntimeException(e); } - })); + } - ex.addToolCategory(aICategory); + SwingUtilities.invokeLater(() -> { + loadingFrame.dispose(); + try { + MainWindow ex = new MainWindow(); + int id = 0; + MainWindow.ToolCategory debugCategory = new MainWindow.ToolCategory("调试工具", + "debug/debug.png", + "用于调试指定Windows工具的一个分类"); - ex.initUI(); - ex.setVisible(true); - }); + debugCategory.addTool(new MainWindow.ToolItem("Frida注入工具", "debug/frida/frida_main.png", + "使用frida注入目标进程的脚本程序 " + + "\n作者:tzdwindows 7", ++id, new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + Window owner = SwingUtilities.windowForComponent((Component) e.getSource()); + FridaWindow fridaWindow = new FridaWindow(owner); + fridaWindow.setVisible(true); + } + })); + + // 在后面注册你自己的项或是添加你自己的分类 + // .... + + ex.addToolCategory(debugCategory); + + MainWindow.ToolCategory aICategory = new MainWindow.ToolCategory("AI工具", + "ai/ai.png", + "人工智能/大语言模型"); + + aICategory.addTool(new MainWindow.ToolItem("本地AI执行工具", "ai/local/local_main.png", + "在本机对开源大语言模型进行推理" + + "\n作者:tzdwindows 7", ++id, new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + Window owner = SwingUtilities.windowForComponent((Component) e.getSource()); + LocalWindow dialog = new LocalWindow(owner); + dialog.setVisible(true); + } + })); + + ex.addToolCategory(aICategory); + + ex.initUI(); + ex.setVisible(true); + } catch (Exception e) { + logger.error("There was a problem starting the main thread", e); + throw new RuntimeException(e); + } + }); + }).start(); } } \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/gui/FridaWindow.java b/src/main/java/com/axis/innovators/box/gui/FridaWindow.java index 3d2e1dd..0571193 100644 --- a/src/main/java/com/axis/innovators/box/gui/FridaWindow.java +++ b/src/main/java/com/axis/innovators/box/gui/FridaWindow.java @@ -1,8 +1,8 @@ package com.axis.innovators.box.gui; -import org.tzd.frida.windows.CallbackMessage; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.tzd.frida.windows.Frida; -import org.tzd.frida.windows.FridaRunnable; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -22,6 +22,7 @@ import java.util.List; * @author tzdwindows 7 */ public class FridaWindow extends JDialog { + private static final Logger logger = LogManager.getLogger(FridaWindow.class); private JTextArea scriptArea; private JTextArea logArea; private JTextField pidField; @@ -149,32 +150,40 @@ public class FridaWindow extends JDialog { Frida frida = new Frida(script, pid); if (!isRepetition) { - frida.run(() -> { - // 执行注入操作 - }).execute(frida1 -> frida1.addCallbackMessage(message -> - SwingUtilities.invokeLater(() -> - logArea.append("[LOG] " + message + "\n") - ) - )).start(); + try { + frida.run(() -> { + }).execute(frida1 -> frida1.addCallbackMessage(message -> + SwingUtilities.invokeLater(() -> { + logger.info("[LOG] {}", message); + logArea.append("[LOG] " + message + "\n"); + }) + )).start(); + } catch (Exception ex) { + logger.error("Injection failure", ex); + throw new RuntimeException(ex); + } isRepetition = true; } else { - frida.run(() -> {}).execute(frida12 -> {}).start(); + try { + frida.run(() -> {}).execute(frida12 -> {}).start(); + } catch (Exception ex) { + logger.error("Injection failure", ex); + } } } catch (NumberFormatException ex) { + logger.error("无效的进程ID", ex); JOptionPane.showMessageDialog(this, "无效的进程ID", "错误", JOptionPane.ERROR_MESSAGE); } } private void openProcessSelectionWindow(ActionEvent e) { - // 打开一个窗口,显示所有进程的ID、名称和图标 ProcessSelectionWindow selectionWindow = new ProcessSelectionWindow(this); selectionWindow.setVisible(true); } - // 选择进程的子窗口 private static class ProcessSelectionWindow extends JDialog { - private List processList; // 存储所有进程信息 + private List processList; private JTable table; public ProcessSelectionWindow(Window owner) { @@ -215,7 +224,6 @@ public class FridaWindow extends JDialog { searchPanel.add(searchField, BorderLayout.CENTER); panel.add(searchPanel, BorderLayout.NORTH); - // 显示进程信息的表格 String[] columns = {"进程名称", "进程ID"}; Object[][] data = getTableData(processList); table = new JTable(data, columns); @@ -239,11 +247,11 @@ public class FridaWindow extends JDialog { private void filterProcesses(String query) { List filteredList = new ArrayList<>(); for (ProcessInfo process : processList) { - if (process.getName().toLowerCase().contains(query.toLowerCase())) { + if (process.name().toLowerCase().contains(query.toLowerCase())) { filteredList.add(process); } } - // 更新表格数据 + Object[][] filteredData = getTableData(filteredList); table.setModel(new DefaultTableModel(filteredData, new String[]{"进程名称", "进程ID"})); } @@ -252,15 +260,18 @@ public class FridaWindow extends JDialog { Object[][] data = new Object[processes.size()][2]; for (int i = 0; i < processes.size(); i++) { ProcessInfo process = processes.get(i); - data[i] = new Object[]{process.getName(), process.getPid()}; + data[i] = new Object[]{process.name(), process.pid()}; } return data; } + /** + * 执行cmd命令获取所有进程信息 + * @return 进程信息列表 + */ private List getProcesses() { List processList = new ArrayList<>(); try { - // 执行cmd命令获取所有进程信息 Process process = Runtime.getRuntime().exec("tasklist /fo csv /nh"); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; @@ -275,28 +286,11 @@ public class FridaWindow extends JDialog { } reader.close(); } catch (IOException e) { - e.printStackTrace(); + logger.error("Failed to get process information ", e); } return processList; } } - // 存储进程信息的类 - private static class ProcessInfo { - private long pid; - private String name; - - public ProcessInfo(long pid, String name) { - this.pid = pid; - this.name = name; - } - - public long getPid() { - return pid; - } - - public String getName() { - return name; - } - } + private record ProcessInfo(long pid, String name) {} } diff --git a/src/main/java/com/axis/innovators/box/gui/LoadIcon.java b/src/main/java/com/axis/innovators/box/gui/LoadIcon.java index afa293e..09cfa88 100644 --- a/src/main/java/com/axis/innovators/box/gui/LoadIcon.java +++ b/src/main/java/com/axis/innovators/box/gui/LoadIcon.java @@ -1,5 +1,8 @@ package com.axis.innovators.box.gui; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; @@ -10,6 +13,7 @@ import java.net.URL; * @author tzdwindows 7 */ public class LoadIcon { + private static final Logger logger = LogManager.getLogger(LoadIcon.class); private static final String ICON_PATH = "/icons/"; public static ImageIcon loadIcon(String filename, int size) { try { @@ -21,6 +25,7 @@ public class LoadIcon { Image image = new ImageIcon(imgUrl).getImage(); return new ImageIcon(image.getScaledInstance(size, size, Image.SCALE_SMOOTH)); } catch (Exception e) { + logger.error("Failed to load icon image path '{}'", filename, e); return createPlaceholderIcon(size); } } diff --git a/src/main/java/com/axis/innovators/box/gui/LocalWindow.java b/src/main/java/com/axis/innovators/box/gui/LocalWindow.java index a86c077..541f3b6 100644 --- a/src/main/java/com/axis/innovators/box/gui/LocalWindow.java +++ b/src/main/java/com/axis/innovators/box/gui/LocalWindow.java @@ -1,5 +1,7 @@ package com.axis.innovators.box.gui; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.tzd.lm.LM; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -8,24 +10,21 @@ import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import java.util.function.Consumer; /** * 本地AI执行工具 * @author tzdwindows 7 */ public class LocalWindow extends JDialog { + private static final Logger logger = LogManager.getLogger(LocalWindow.class); private final Color bgColor = new Color(45, 45, 48); private final Color textColor = new Color(240, 240, 240); private final Font mainFont = new Font("微软雅黑", Font.PLAIN, 14); private final Color bgColor1 = new Color(235, 241, 250); private final Color bgColor2 = new Color(255, 255, 255); - private final Color userTextColor = new Color(0, 100, 200); - private final Color aiTextColor = new Color(0, 150, 0); // AI消息绿色 private JTextArea chatArea; private JTextField inputField; - private JButton sendButton; private JProgressBar progressBar; private JComboBox contextBox; private final LinkedList contextHandles = new LinkedList<>(); @@ -40,19 +39,7 @@ public class LocalWindow extends JDialog { } private void initializeUI() { - // 主面板设置 - JPanel mainPanel = new JPanel(new BorderLayout()) { - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - Graphics2D g2d = (Graphics2D) g; - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - GradientPaint gp = new GradientPaint(0, 0, bgColor1, getWidth(), getHeight(), bgColor2); - g2d.setPaint(gp); - g2d.fillRect(0, 0, getWidth(), getHeight()); - } - }; - mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + JPanel mainPanel = getjPanel(); // 聊天区域 chatArea = new JTextArea(); @@ -88,6 +75,22 @@ public class LocalWindow extends JDialog { this.setLocationRelativeTo(getOwner()); } + private JPanel getjPanel() { + JPanel mainPanel = new JPanel(new BorderLayout()) { + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + GradientPaint gp = new GradientPaint(0, 0, bgColor1, getWidth(), getHeight(), bgColor2); + g2d.setPaint(gp); + g2d.fillRect(0, 0, getWidth(), getHeight()); + } + }; + mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + return mainPanel; + } + private JToolBar createToolBar() { JToolBar toolBar = new JToolBar(); toolBar.setFloatable(false); @@ -135,11 +138,10 @@ public class LocalWindow extends JDialog { inputField.setForeground(Color.black); inputField.setBackground(Color.white); - sendButton = new JButton("发送"); + JButton sendButton = new JButton("发送"); styleButton(sendButton); sendButton.addActionListener(this::handleSendMessage); - // 温度调节 tempSpinner = new JSpinner(new SpinnerNumberModel(0.8, 0.0, 1.0, 0.1)); tempSpinner.setFont(mainFont); tempSpinner.setBackground(bgColor); @@ -177,6 +179,7 @@ public class LocalWindow extends JDialog { currentModelHandle = get(); createNewContext(); } catch (Exception ex) { + logger.error("Model loading failed , loading location {}", LM.DEEP_SEEK ,ex); JOptionPane.showMessageDialog(LocalWindow.this, "模型加载失败"); } progressBar.setVisible(false); @@ -192,7 +195,7 @@ public class LocalWindow extends JDialog { contextBox.setSelectedIndex(contextHandles.size()-1); contextBox.setBackground(Color.lightGray); contextBox.setForeground(Color.black); - chatArea.setText(""); // 清除聊天区域内容 + chatArea.setText(""); } } @@ -219,16 +222,26 @@ public class LocalWindow extends JDialog { protected void process(java.util.List chunks) { chunks.forEach(msg -> appendAIMessage(msg)); } + + @Override + protected void done() { + try { + String result = get(); + logger.info(result); + } catch (Exception ex) { + logger.error("SwingWorker execution error: ", ex); + } + } }.execute(); } } static boolean isTemporary = true; - private final List messages = new ArrayList<>(); private void appendAIMessage(String message) { SwingUtilities.invokeLater(() -> { if (isTemporary) { chatArea.append("【AI】\n"); + logger.info("【AI】"); isTemporary = false; } // 处理Markdown语法 @@ -237,27 +250,33 @@ public class LocalWindow extends JDialog { .replaceAll("", ""); chatArea.append(message2); chatArea.setCaretPosition(chatArea.getDocument().getLength()); - messages.add(message2); }); } private void appendMessage(String message) { SwingUtilities.invokeLater(() -> { + logger.info("\n【用户】\n{}", message); chatArea.append("\n【用户】\n" + message + "\n\n"); chatArea.setCaretPosition(chatArea.getDocument().getLength()); }); } private void saveConversation() { - String content = chatArea.getText(); + //String content = chatArea.getText(); // TODO: 调用保存实现 } @Override public void dispose() { - contextHandles.forEach(LM::llamaFreeContext); + if (contextHandles.isEmpty()){ + logger.warn("No context to free"); + } else { + contextHandles.forEach(LM::llamaFreeContext); + } if (currentModelHandle != -1) { LM.llamaFreeModel(currentModelHandle); + } else { + logger.warn("Wrong model handle"); } super.dispose(); } diff --git a/src/main/java/com/axis/innovators/box/gui/MainWindow.java b/src/main/java/com/axis/innovators/box/gui/MainWindow.java index e750548..dfc2064 100644 --- a/src/main/java/com/axis/innovators/box/gui/MainWindow.java +++ b/src/main/java/com/axis/innovators/box/gui/MainWindow.java @@ -1,6 +1,8 @@ package com.axis.innovators.box.gui; import com.axis.innovators.box.events.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import javax.swing.*; import javax.swing.Timer; @@ -9,7 +11,6 @@ import javax.swing.plaf.basic.BasicScrollBarUI; import javax.swing.plaf.basic.BasicTabbedPaneUI; import java.awt.*; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; @@ -23,6 +24,7 @@ import java.util.List; * @author tzdwindows 7 */ public class MainWindow extends JFrame { + private static final Logger logger = LogManager.getLogger(MainWindow.class); private final Map cardScales = new HashMap<>(); private final Map cardElevations = new HashMap<>(); // 选项卡颜色 @@ -81,7 +83,7 @@ public class MainWindow extends JFrame { g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); } catch (Exception e) { - e.printStackTrace(); + logger.error("Failed to load background image", e); } } } @@ -271,11 +273,6 @@ public class MainWindow extends JFrame { JPanel content = new JPanel(new BorderLayout()); content.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); - //JLabel placeholder = new JLabel("设置功能开发中...", SwingConstants.CENTER); - //placeholder.setFont(new Font("微软雅黑", Font.PLAIN, 24)); - //placeholder.setForeground(new Color(127, 140, 153)); - //content.add(placeholder, BorderLayout.CENTER); - GlobalEventBus.EVENT_BUS.post(new SettingsLoadEvents(dialog, content)); dialog.add(content); @@ -373,40 +370,6 @@ public class MainWindow extends JFrame { return card; } - private BufferedImage captureWindowImage(Window window) { - try { - Rectangle bounds = window.getBounds(); - BufferedImage capture = new Robot().createScreenCapture(bounds); - return capture.getSubimage(0, 0, window.getWidth(), window.getHeight()); - } catch (AWTException e) { - e.printStackTrace(); - return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); - } - } - - private static JPanel getjPanel(BufferedImage[] blurredImage, Window window) { - JPanel blurPanel = new JPanel() { - private float currentOpacity = 1.0f; - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - - if (blurredImage[0] != null) { - Graphics2D g2d = (Graphics2D) g.create(); - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, currentOpacity)); - g2d.drawImage(blurredImage[0], 0, 0, null); - g2d.dispose(); - } - } - }; - - // 面板属性设置 - blurPanel.setBounds(0, 0, window.getWidth(), window.getHeight()); - blurPanel.setOpaque(false); - return blurPanel; - } - private String createToolTipHTML(ToolItem tool) { return "" + @@ -415,40 +378,6 @@ public class MainWindow extends JFrame { ""; } - private void animateHover(JComponent component, float targetScale, int targetElevation) { - final int ANIMATION_DURATION = 200; - final float startScale = cardScales.getOrDefault(component, 1.0f); - final int startElevation = cardElevations.getOrDefault(component, 2); - - new Timer(10, new AbstractAction() { - long startTime = -1; - - @Override - public void actionPerformed(ActionEvent e) { - if (startTime < 0) { - startTime = System.currentTimeMillis(); - } - long elapsed = System.currentTimeMillis() - startTime; - float progress = Math.min(1.0f, elapsed / (float) ANIMATION_DURATION); - - // 使用缓动函数实现平滑动画 - float easedProgress = (float) (1 - Math.pow(1 - progress, 3)); - - float currentScale = startScale + (targetScale - startScale) * easedProgress; - int currentElevation = (int) (startElevation + (targetElevation - startElevation) * easedProgress); - - cardScales.put(component, currentScale); - cardElevations.put(component, currentElevation); - - component.repaint(); - - if (progress >= 1.0f) { - ((Timer) e.getSource()).stop(); - } - } - }).start(); - } - // 工具类别内部类 public static class ToolCategory { private final String name; @@ -504,30 +433,6 @@ public class MainWindow extends JFrame { * @param action 工具的点击事件 */ public record ToolItem(String title, String icon, String description, int id, Action action) { - private static JPanel getjPanel() { - JPanel content = new JPanel() { - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - - // 渐变背景 - GradientPaint gp = new GradientPaint( - 0, 0, new Color(245, 247, 250), - getWidth(), getHeight(), new Color(255, 255, 255) - ); - g2d.setPaint(gp); - g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 20, 20); - - // 边框阴影 - g2d.setColor(new Color(0, 0, 0, 20)); - g2d.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 20, 20); - } - }; - content.setLayout(new BorderLayout(20, 20)); - content.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); - return content; - } public String getName() { return title; diff --git a/src/main/java/com/axis/innovators/box/plugins/PluginDescriptor.java b/src/main/java/com/axis/innovators/box/plugins/PluginDescriptor.java new file mode 100644 index 0000000..a14947f --- /dev/null +++ b/src/main/java/com/axis/innovators/box/plugins/PluginDescriptor.java @@ -0,0 +1,29 @@ +package com.axis.innovators.box.plugins; + +import java.util.List; + +/** + * @author tzdwindows 7 + */ +public class PluginDescriptor { + private String id; + private String name; + private List supportedVersions; + private String icon; + private String description; + private Object instance; + + // Getters and Setters + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public String getName() { return name; } + public void setName(String name) { this.name = name; } + public List getSupportedVersions() { return supportedVersions; } + public void setSupportedVersions(List supportedVersions) { this.supportedVersions = supportedVersions; } + public String getIcon() { return icon; } + public void setIcon(String icon) { this.icon = icon; } + public String getDescription() { return description; } + public void setDescription(String description) { this.description = description; } + public Object getInstance() { return instance; } + public void setInstance(Object instance) { this.instance = instance; } +} diff --git a/src/main/java/com/axis/innovators/box/plugins/PluginLoader.java b/src/main/java/com/axis/innovators/box/plugins/PluginLoader.java new file mode 100644 index 0000000..434683a --- /dev/null +++ b/src/main/java/com/axis/innovators/box/plugins/PluginLoader.java @@ -0,0 +1,148 @@ +package com.axis.innovators.box.plugins; + +import com.axis.innovators.box.Main; +import com.axis.innovators.box.tools.FolderCreator; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.jar.*; + +/** + * 加载插件的系统 + * @author tzdwindows 7 + */ +public class PluginLoader { + private static final Logger logger = LogManager.getLogger(PluginLoader.class); + public static final String PLUGIN_PATH = FolderCreator.getPluginFolder(); + private static final List loadedPlugins = new ArrayList<>(); + + /** + * 加载插件 + * @throws IOException 插件加载失败 + */ + public static void loadPlugins() throws IOException { + File pluginDir = new File(PLUGIN_PATH); + File[] jars = pluginDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".jar")); + + if (jars == null) { + return; + } + Main.totalTasks = jars.length; + for (int i = 0; i < jars.length; i++) { + processJarFile(jars[i]); + Main.completedTasks = i; + } + } + + private static void processJarFile(File jarFile) throws IOException { + try (JarFile jar = new JarFile(jarFile)) { + JarEntry pluginFile = jar.getJarEntry("plug-in.box"); + if (pluginFile != null) { + processWithManifest(jar, pluginFile, jarFile); + } else { + processWithAnnotations(jar, jarFile); + } + } + } + + private static void processWithManifest(JarFile jar, JarEntry entry, File jarFile) { + Properties props = new Properties(); + try (InputStream is = jar.getInputStream(entry)) { + props.load(is); + } catch (IOException e) { + logger.error("Failed to load plugin from jar: {}", jarFile.getName(), e); + return; + } + + PluginDescriptor descriptor = new PluginDescriptor(); + descriptor.setId(props.getProperty("id")); + descriptor.setName(props.getProperty("name")); + descriptor.setDescription(props.getProperty("description")); + descriptor.setIcon(props.getProperty("icon")); + descriptor.setSupportedVersions( + Arrays.asList(props.getProperty("supportedVersions").split(",")) + ); + + loadMainClass(props.getProperty("mainClass"), jarFile, descriptor); + if (descriptor.getInstance() != null) { + loadedPlugins.add(descriptor); + } + } + + private static void processWithAnnotations(JarFile jar, File jarFile) { + URLClassLoader classLoader = createClassLoader(jarFile); + Enumeration entries = jar.entries(); + + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.getName().endsWith(".class")) { + processClassEntry(entry, classLoader); + } + } + } + + private static URLClassLoader createClassLoader(File jarFile) { + try { + return new URLClassLoader( + new URL[]{jarFile.toURI().toURL()}, + PluginLoader.class.getClassLoader() + ); + } catch (MalformedURLException e) { + logger.error("Error creating URLClassLoader", e); + } + return null; + } + + private static void processClassEntry(JarEntry entry, URLClassLoader classLoader) { + String className = entry.getName() + .replace("/", ".") + .replace(".class", ""); + + try { + Class clazz = classLoader.loadClass(className); + PluginMeta meta = clazz.getAnnotation(PluginMeta.class); + if (meta != null) { + PluginDescriptor descriptor = new PluginDescriptor(); + descriptor.setId(meta.id()); + descriptor.setName(meta.name()); + descriptor.setDescription(meta.description()); + descriptor.setIcon(meta.icon()); + descriptor.setSupportedVersions(Arrays.asList(meta.supportedVersions())); + + try { + Object instance = clazz.getDeclaredConstructor().newInstance(); + descriptor.setInstance(instance); + loadedPlugins.add(descriptor); + } catch (Exception e) { + logger.error("Failed to instantiate plugin class: {}", className, e); + } + } + } catch (ClassNotFoundException | NoClassDefFoundError e) { + logger.error("Error loading class: {}", className, e); + } + } + + private static void loadMainClass(String mainClassName, File jarFile, PluginDescriptor descriptor) { + if (mainClassName == null || mainClassName.isEmpty()) { + return; + } + + try (URLClassLoader classLoader = new URLClassLoader( + new URL[]{jarFile.toURI().toURL()}, + PluginLoader.class.getClassLoader()) + ) { + Class mainClass = classLoader.loadClass(mainClassName); + Object instance = mainClass.getDeclaredConstructor().newInstance(); + descriptor.setInstance(instance); + } catch (Exception e) { + logger.error("Failed to load main class: {}", mainClassName, e); + } + } + + public static List getLoadedPlugins() { + return Collections.unmodifiableList(loadedPlugins); + } +} \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/plugins/PluginMeta.java b/src/main/java/com/axis/innovators/box/plugins/PluginMeta.java new file mode 100644 index 0000000..ca2a19d --- /dev/null +++ b/src/main/java/com/axis/innovators/box/plugins/PluginMeta.java @@ -0,0 +1,20 @@ +package com.axis.innovators.box.plugins; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author tzdwindows 7 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface PluginMeta { + String id(); + String name(); + String[] supportedVersions(); + String description(); + String icon() default ""; +} \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/tools/FolderCreator.java b/src/main/java/com/axis/innovators/box/tools/FolderCreator.java index b190cce..b6dcb57 100644 --- a/src/main/java/com/axis/innovators/box/tools/FolderCreator.java +++ b/src/main/java/com/axis/innovators/box/tools/FolderCreator.java @@ -1,5 +1,8 @@ package com.axis.innovators.box.tools; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.io.File; /** @@ -7,14 +10,24 @@ import java.io.File; * @author tzdwindows 7 */ public class FolderCreator { - + private static final Logger logger = LogManager.getLogger(FolderCreator.class); public static final String LIBRARY_NAME = "library"; public static final String MODEL_PATH = "model"; + public static final String PLUGIN_PATH = "plug-in"; + + public static String getPluginFolder() { + String folder = createFolder(PLUGIN_PATH); + if (folder == null) { + logger.error("Plugin folder creation failed, please use administrator privileges to execute this procedure"); + return null; + } + return folder; + } public static String getModelFolder() { String folder = createFolder(MODEL_PATH); if (folder == null) { - System.out.println("Model folder creation failure"); + logger.error("Model folder creation failure, please use administrator privileges to execute this procedure"); return null; } return folder; @@ -23,7 +36,7 @@ public class FolderCreator { public static String getLibraryFolder() { String folder = createFolder(LIBRARY_NAME); if (folder == null) { - System.out.println("Library folder creation failure"); + logger.error("Library folder creation failed, please use administrator privileges to execute this procedure"); return null; } return folder; @@ -39,7 +52,7 @@ public class FolderCreator { File folder = new File(jarDir, folderName); if (!folder.exists()) { if (!folder.mkdir()) { - System.out.println("Folder creation failure"); + logger.error("Folder creation failure"); return null; } } diff --git a/src/main/java/com/axis/innovators/box/tools/SystemInfoUtil.java b/src/main/java/com/axis/innovators/box/tools/SystemInfoUtil.java new file mode 100644 index 0000000..b267dc5 --- /dev/null +++ b/src/main/java/com/axis/innovators/box/tools/SystemInfoUtil.java @@ -0,0 +1,95 @@ +package com.axis.innovators.box.tools; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + + +/** + * 获取用户计算机信息 + * @author tzdwindows 7 + */ +public class SystemInfoUtil { + private static final Logger logger = LogManager.getLogger(SystemInfoUtil.class); + + /** + * 获取操作系统架构 + */ + public static String getOSArch() { + return System.getProperty("os.arch"); + } + + /** + * 获取操作系统名称 + */ + public static String getOSName() { + return System.getProperty("os.name"); + } + + /** + * 获取 CPU 信息 + */ + public static String getCPUInfo() { + try { + if (System.getProperty("os.name").toLowerCase().contains("win")) { + // Windows 系统 + Process process = Runtime.getRuntime().exec("wmic cpu get name"); + return getString(process); + } else if (System.getProperty("os.name").toLowerCase().contains("linux")) { + // Linux 系统 + Process process = Runtime.getRuntime().exec("lscpu"); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + if (line.contains("Model name")) { + return line.split(":")[1].trim(); + } + } + } + } catch (Exception e) { + logger.error("Failed to get CPU info", e); + } + return "Unknown CPU"; + } + + /** + * 获取 GPU 信息 + */ + public static String getGPUInfo() { + try { + if (System.getProperty("os.name").toLowerCase().contains("win")) { + // Windows 系统 + Process process = Runtime.getRuntime().exec("wmic path win32_videocontroller get name"); + return getString(process); + } else if (System.getProperty("os.name").toLowerCase().contains("linux")) { + // Linux 系统 + Process process = Runtime.getRuntime().exec("lspci | grep VGA"); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line = reader.readLine(); + if (line != null) { + return line.split(":")[2].trim(); + } + } + } catch (Exception e) { + logger.error("Failed to get GPU info", e); + } + return "Unknown GPU"; + } + + private static String getString(Process process) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + List gpuInfo = new ArrayList<>(); + while ((line = reader.readLine()) != null) { + if (!line.trim().isEmpty() && !line.contains("Name")) { + gpuInfo.add(line.trim()); + } + } + return String.join(", ", gpuInfo); + } +} diff --git a/src/main/java/org/tzd/lm/LM.java b/src/main/java/org/tzd/lm/LM.java index 6e1b4b0..e845479 100644 --- a/src/main/java/org/tzd/lm/LM.java +++ b/src/main/java/org/tzd/lm/LM.java @@ -2,6 +2,8 @@ package org.tzd.lm; import com.axis.innovators.box.tools.FolderCreator; import com.axis.innovators.box.tools.LibraryLoad; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * LM推理类 @@ -10,21 +12,32 @@ import com.axis.innovators.box.tools.LibraryLoad; public class LM { public static boolean CUDA = true; public final static String DEEP_SEEK = FolderCreator.getModelFolder() + "\\DeepSeek-R1-Distill-Qwen-1.5B-Q8_0.gguf"; + private static final Logger logger = LogManager.getLogger(LM.class); static { if (!CUDA) { + logger.warn("The cpu will be used for inference"); LibraryLoad.loadLibrary("cpu/ggml-base"); LibraryLoad.loadLibrary("cpu/ggml-cpu"); LibraryLoad.loadLibrary("cpu/ggml"); LibraryLoad.loadLibrary("cpu/llama"); } else { - LibraryLoad.loadLibrary("cuda/ggml-base"); - LibraryLoad.loadLibrary("cuda/ggml-cpu"); - LibraryLoad.loadLibrary("cuda/ggml-rpc"); - // cuda版本 cuda-cu12.4-x64(确保你有) - LibraryLoad.loadLibrary("cuda/ggml-cuda"); - LibraryLoad.loadLibrary("cuda/ggml"); - LibraryLoad.loadLibrary("cuda/llama"); + try { + LibraryLoad.loadLibrary("cuda/ggml-base"); + LibraryLoad.loadLibrary("cuda/ggml-cpu"); + LibraryLoad.loadLibrary("cuda/ggml-rpc"); + // cuda版本 cuda-cu12.4-x64(确保你有) + LibraryLoad.loadLibrary("cuda/ggml-cuda"); + LibraryLoad.loadLibrary("cuda/ggml"); + LibraryLoad.loadLibrary("cuda/llama"); + } catch (Exception e) { + logger.error("Wrong cuda Settings", e); + logger.warn("The cuda library could not be loaded, the cpu will be used for inference"); + LibraryLoad.loadLibrary("cpu/ggml-base"); + LibraryLoad.loadLibrary("cpu/ggml-cpu"); + LibraryLoad.loadLibrary("cpu/ggml"); + LibraryLoad.loadLibrary("cpu/llama"); + } } LibraryLoad.loadLibrary("LM"); } diff --git a/src/main/java/org/tzd/lm/LMApi.java b/src/main/java/org/tzd/lm/LMApi.java index 3f46beb..9506b09 100644 --- a/src/main/java/org/tzd/lm/LMApi.java +++ b/src/main/java/org/tzd/lm/LMApi.java @@ -13,6 +13,7 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; /** + * 使用AI接口获取回复 * @author tzdwindows 7 */ public class LMApi { diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..ef41df4 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n + + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + + + + + + + \ No newline at end of file