feat(AI工具): 添加本地AI执行工具

- 新增LocalWindow类,实现本地AI推理功能- 更新LM类,添加推理相关方法
- 在Main类中添加AI工具类别和本地AI执行工具项
- 优化FridaWindow类,添加作者注释
This commit is contained in:
tzdwindows 7
2025-02-07 18:03:51 +08:00
parent ebde6b1d1d
commit 022446eb32
7 changed files with 408 additions and 20 deletions

View File

@@ -4,6 +4,7 @@ import com.axis.innovators.box.events.GlobalEventBus;
import com.axis.innovators.box.events.SettingsLoadEvents;
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.tools.FolderCreator;
import com.axis.innovators.box.tools.LibraryLoad;
@@ -63,6 +64,24 @@ public class Main {
// ....
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);
});

View File

@@ -17,6 +17,10 @@ import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
/**
* Frida注入工具窗口
* @author tzdwindows 7
*/
public class FridaWindow extends JDialog {
private JTextArea scriptArea;
private JTextArea logArea;

View File

@@ -0,0 +1,263 @@
package com.axis.innovators.box.gui;
import org.tzd.lm.LM;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
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 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<String> contextBox;
private final LinkedList<Long> contextHandles = new LinkedList<>();
private long currentModelHandle = -1;
private JSpinner tempSpinner;
public LocalWindow(Window owner) {
super(owner, "本地AI执行工具", ModalityType.APPLICATION_MODAL);
initializeUI();
loadModelAsync();
}
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));
// 聊天区域
chatArea = new JTextArea();
chatArea.setEditable(false);
chatArea.setFont(mainFont);
chatArea.setForeground(textColor);
chatArea.setOpaque(false);
chatArea.setLineWrap(true);
chatArea.setWrapStyleWord(true);
chatArea.setBackground(Color.lightGray);
chatArea.setForeground(Color.black);
JScrollPane scrollPane = new JScrollPane(chatArea);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
JToolBar toolBar = createToolBar();
JPanel inputPanel = createInputPanel();
progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
progressBar.setVisible(false);
mainPanel.add(toolBar, BorderLayout.NORTH);
mainPanel.add(scrollPane, BorderLayout.CENTER);
mainPanel.add(inputPanel, BorderLayout.SOUTH);
mainPanel.add(scrollPane, BorderLayout.CENTER);
this.add(mainPanel);
this.setSize(800, 600);
this.setLocationRelativeTo(getOwner());
}
private JToolBar createToolBar() {
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.setBackground(bgColor);
// 新对话按钮
JButton newBtn = new JButton("新对话");
styleButton(newBtn);
newBtn.addActionListener(e -> createNewContext());
// 保存记录按钮
JButton saveBtn = new JButton("保存记录");
styleButton(saveBtn);
saveBtn.addActionListener(e -> saveConversation());
// CUDA切换
JCheckBox cudaCheck = new JCheckBox("启用CUDA", LM.CUDA);
cudaCheck.setFont(mainFont);
cudaCheck.setBackground(Color.lightGray);
cudaCheck.setForeground(Color.black);
cudaCheck.addActionListener(e -> LM.CUDA = cudaCheck.isSelected());
// 上下文选择
contextBox = new JComboBox<>();
contextBox.setBackground(bgColor);
contextBox.setForeground(textColor);
toolBar.add(newBtn);
toolBar.add(saveBtn);
toolBar.addSeparator();
toolBar.add(cudaCheck);
toolBar.addSeparator();
toolBar.add(contextBox);
return toolBar;
}
private JPanel createInputPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBackground(bgColor);
inputField = new JTextField();
inputField.setFont(mainFont);
inputField.setForeground(Color.black);
inputField.setBackground(Color.white);
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);
tempSpinner.setForeground(textColor);
tempSpinner.setPreferredSize(new Dimension(80, tempSpinner.getPreferredSize().height));
JPanel rightPanel = new JPanel(new BorderLayout());
rightPanel.add(tempSpinner, BorderLayout.WEST);
rightPanel.add(sendButton, BorderLayout.EAST);
panel.add(inputField, BorderLayout.CENTER);
panel.add(rightPanel, BorderLayout.EAST);
return panel;
}
private void styleButton(JButton button) {
button.setFont(mainFont);
button.setBackground(Color.lightGray);
button.setForeground(Color.black);
button.setFocusPainted(false);
button.setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
}
private void loadModelAsync() {
progressBar.setVisible(true);
new SwingWorker<Long, Void>() {
@Override
protected Long doInBackground() {
return LM.llamaLoadModelFromFile(LM.DEEP_SEEK);
}
@Override
protected void done() {
try {
currentModelHandle = get();
createNewContext();
} catch (Exception ex) {
JOptionPane.showMessageDialog(LocalWindow.this, "模型加载失败");
}
progressBar.setVisible(false);
}
}.execute();
}
private void createNewContext() {
if (currentModelHandle != -1) {
long newCtx = LM.createContext(currentModelHandle);
contextHandles.add(newCtx);
contextBox.addItem("上下文 " + contextHandles.size());
contextBox.setSelectedIndex(contextHandles.size()-1);
contextBox.setBackground(Color.lightGray);
contextBox.setForeground(Color.black);
chatArea.setText(""); // 清除聊天区域内容
}
}
private void handleSendMessage(ActionEvent e) {
String prompt = inputField.getText();
if (!prompt.isEmpty()) {
appendMessage(prompt);
inputField.setText("");
new SwingWorker<String, String>() {
@Override
protected String doInBackground() {
float temperature = ((Number) tempSpinner.getValue()).floatValue();
return LM.inference(
currentModelHandle,
contextHandles.getLast(),
temperature,
prompt,
this::publish
);
}
@Override
protected void process(java.util.List<String> chunks) {
chunks.forEach(msg -> appendAIMessage(msg));
}
}.execute();
}
}
static boolean isTemporary = true;
private final List<String> messages = new ArrayList<>();
private void appendAIMessage(String message) {
SwingUtilities.invokeLater(() -> {
if (isTemporary) {
chatArea.append("【AI】\n");
isTemporary = false;
}
// 处理Markdown语法
String message2 = message.replaceAll("\\*\\*(.*?)\\*\\*", "<b>$1</b>")
.replaceAll("##(.*?)\\n", "<h2>$1</h2>")
.replaceAll("</think>", "</think></fold>");
chatArea.append(message2);
chatArea.setCaretPosition(chatArea.getDocument().getLength());
messages.add(message2);
});
}
private void appendMessage(String message) {
SwingUtilities.invokeLater(() -> {
chatArea.append("\n【用户】\n" + message + "\n\n");
chatArea.setCaretPosition(chatArea.getDocument().getLength());
});
}
private void saveConversation() {
String content = chatArea.getText();
// TODO: 调用保存实现
}
@Override
public void dispose() {
contextHandles.forEach(LM::llamaFreeContext);
if (currentModelHandle != -1) {
LM.llamaFreeModel(currentModelHandle);
}
super.dispose();
}
}