From d53fe66e378a752c5deaf5712c0b35b98be16868 Mon Sep 17 00:00:00 2001
From: tzdwindows 7 <3076584115@qq.com>
Date: Sun, 23 Mar 2025 18:48:13 +0800
Subject: [PATCH] =?UTF-8?q?feat(browser):=20=E5=AE=9E=E7=8E=B0=20AI=20?=
=?UTF-8?q?=E6=8E=A8=E7=90=86=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E8=81=8A=E5=A4=A9=E7=95=8C=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 AI 推理相关功能,包括模型加载、上下文创建和消息处理
- 设计并实现聊天界面的前端逻辑,支持流式响应和消息折叠
- 集成 KaTeX、highlight.js 和 marked 库,支持数学公式和代码高亮显示
- 添加错误处理和友好的用户交互提示
---
.idea/encodings.xml | 10 +
.idea/jsLibraryMappings.xml | 6 +
.../box/browser/DeepSeek - 探索未至之境.html | 688 ++++++++++++++++++
.../box/browser/MainApplication.java | 156 +++-
.../box/browser/WindowOperation.java | 7 +-
.../box/browser/WindowOperationHandler.java | 2 +-
src/main/java/org/tzd/lm/LM.java | 40 +-
7 files changed, 894 insertions(+), 15 deletions(-)
create mode 100644 .idea/encodings.xml
create mode 100644 .idea/jsLibraryMappings.xml
create mode 100644 src/main/java/com/axis/innovators/box/browser/DeepSeek - 探索未至之境.html
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..736d22b
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml
new file mode 100644
index 0000000..02b6bbf
--- /dev/null
+++ b/.idea/jsLibraryMappings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/axis/innovators/box/browser/DeepSeek - 探索未至之境.html b/src/main/java/com/axis/innovators/box/browser/DeepSeek - 探索未至之境.html
new file mode 100644
index 0000000..b97d636
--- /dev/null
+++ b/src/main/java/com/axis/innovators/box/browser/DeepSeek - 探索未至之境.html
@@ -0,0 +1,688 @@
+
+
+
+
+
+ DeepSeek - 智能助手
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/axis/innovators/box/browser/MainApplication.java b/src/main/java/com/axis/innovators/box/browser/MainApplication.java
index 4e6bb93..7c4414e 100644
--- a/src/main/java/com/axis/innovators/box/browser/MainApplication.java
+++ b/src/main/java/com/axis/innovators/box/browser/MainApplication.java
@@ -1,34 +1,168 @@
package com.axis.innovators.box.browser;
+import org.cef.browser.CefBrowser;
+import org.cef.browser.CefFrame;
+import org.cef.browser.CefMessageRouter;
+import org.cef.callback.CefQueryCallback;
+import org.cef.handler.CefMessageRouterHandlerAdapter;
+import org.tzd.lm.LM;
+
import javax.swing.*;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
/**
* 这是一个简单的示例程序,用于展示如何使用JCEF来创建一个简单的浏览器窗口。
*/
public class MainApplication {
+ private static final ExecutorService executor = Executors.newCachedThreadPool();
+ private static long modelHandle;
+ private static long ctxHandle;
+ private static boolean isSystem = true;
public static void main(String[] args) {
- SwingUtilities.invokeLater(() -> {
- //if (!CefApp.startup(args)) {
- // System.out.println("Startup initialization failed!");
- // return;
- //}
+ LM.loadLibrary(LM.CUDA);
+ modelHandle = LM.llamaLoadModelFromFile(LM.DEEP_SEEK);
+ ctxHandle = LM.createContext(modelHandle);
+ AtomicReference window = new AtomicReference<>();
+ SwingUtilities.invokeLater(() -> {
WindowRegistry.getInstance().createNewWindow("main", builder ->
- builder.title("Axis Innovators Box")
+ window.set(builder.title("Axis Innovators Box")
.size(1280, 720)
- .htmlPath("C:\\Users\\Administrator\\MCreatorWorkspaces\\AxisInnovatorsBox\\src\\main\\java\\com\\axis\\innovators\\box\\browser\\main.html")
+ .htmlPath("C:\\Users\\Administrator\\MCreatorWorkspaces\\AxisInnovatorsBox\\src\\main\\java\\com\\axis\\innovators\\box\\browser\\DeepSeek - 探索未至之境.html")
.operationHandler(createOperationHandler())
- .build()
+ .build())
);
+
+ CefMessageRouter msgRouter = window.get().getMsgRouter();
+ if (msgRouter != null) {
+ msgRouter.addHandler(new CefMessageRouterHandlerAdapter() {
+ @Override
+ public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId,
+ String request, boolean persistent, CefQueryCallback callback) {
+ // 处理浏览器请求
+ handleBrowserQuery(browser, request, callback);
+ return true;
+ }
+
+ @Override
+ public void onQueryCanceled(CefBrowser browser, CefFrame frame, long queryId) {
+ // 处理请求取消
+ }
+ }, true);
+ }
});
+
+ // 关闭钩子
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ LM.llamaFreeContext(ctxHandle);
+ LM.llamaFreeModel(modelHandle);
+ executor.shutdown();
+ }));
+ }
+
+ private static void handleBrowserQuery(CefBrowser browser, String request, CefQueryCallback callback) {
+ try {
+ String[] parts = request.split(":", 3);
+ if (parts.length < 3) {
+ callback.failure(400, "请求格式错误");
+ return;
+ }
+
+ String operation = parts[0];
+ String requestId = parts[1];
+ String prompt = parts[2];
+
+ if ("ai-inference".equals(operation)) {
+ executor.execute(() -> {
+ //String system;
+ if (isSystem) {
+ //system = ;
+ isSystem = false;
+ } //else {
+ //system = null;
+ //}
+ List messageList = new java.util.ArrayList<>(List.of());
+ // 修改后的推理回调处理
+ String jsCode = String.format(
+ "if (typeof updateResponse === 'function') {" +
+ " updateResponse('%s', '%s');" +
+ "}",
+ requestId, "" +
+ "\\n" +
+ "推理内容
"
+ );
+ browser.executeJavaScript(jsCode, null, 0);
+ LM.inference(modelHandle, ctxHandle, 0.6f, prompt + "\n",
+ """
+ # 角色设定
+ 你是一个严格遵循规则的AI助手,
+ 当遇到简单的问题时你可以直接回答(回答先添加),在遇到复杂问题时请你思考后再给出答案,并且需满足以下要求:
+
+ ## 核心指令
+ 1. **强制推理标记**:无论是否推理,回答**必须**以``开头,推理结束时闭合``。
+ 2. **推理流程**:
+ - 使用固定句式(如“好的,用户现在需要...”)启动分析
+ 3. **回答规范**:
+ - 使用Markdown标题、列表、加粗突出重点
+ - LaTeX公式严格包裹在`$$...$$`中(示例:`$$E=mc^2$$`)
+ - 不同可能性答案用列表呈现
+
+ ## 违规惩罚
+ - 若未包含``标签,需在回答开头添加
+ """,
+ new LM.MessageCallback() {
+ private boolean thinkingClosed = false;
+
+ @Override
+ public void onMessage(String message) {
+ messageList.add(message);
+ SwingUtilities.invokeLater(() -> {
+ // 统一转义处理
+ String escaped = message
+ .replace("\\", "\\\\")
+ .replace("'", "\\'")
+ .replace("\"", "\\\"")
+ .replace("\n", "\\n")
+ .replace("\r", "\\r");
+
+ if (messageList.contains("") && !thinkingClosed) {
+ String endJs = String.format(
+ "if (typeof updateResponse === 'function') {" +
+ " updateResponse('%s', '%s');" +
+ "}",
+ requestId, " "
+ );
+ browser.executeJavaScript(endJs, null, 0);
+ thinkingClosed = true;
+ }
+
+ // 实时更新内容
+ String jsCode = String.format(
+ "if (typeof updateResponse === 'function') {" +
+ " updateResponse('%s', '%s');" +
+ "}",
+ requestId, escaped
+ );
+ browser.executeJavaScript(jsCode, null, 0);
+ });
+ }
+ },isSystem);
+ messageList.clear();
+ callback.success("COMPLETED:" + requestId);
+ });
+ }
+ } catch (Exception e) {
+ callback.failure(500, "服务器错误: " + e.getMessage());
+ }
}
private static WindowOperationHandler createOperationHandler() {
return new WindowOperationHandler.Builder()
.withDefaultOperations()
- .onOperation("我是注册的指令", s -> {
-
- })
.build();
}
}
diff --git a/src/main/java/com/axis/innovators/box/browser/WindowOperation.java b/src/main/java/com/axis/innovators/box/browser/WindowOperation.java
index f9f4d00..886aeb6 100644
--- a/src/main/java/com/axis/innovators/box/browser/WindowOperation.java
+++ b/src/main/java/com/axis/innovators/box/browser/WindowOperation.java
@@ -2,15 +2,18 @@ package com.axis.innovators.box.browser;
import org.cef.callback.CefQueryCallback;
+/**
+ * @author tzdwindows 7
+ */
public class WindowOperation {
private final String type;
private final String targetWindow;
private final CefQueryCallback callback;
- public WindowOperation(String type, String targetWindow, CefQueryCallback callback) { // [!code ++]
+ public WindowOperation(String type, String targetWindow, CefQueryCallback callback) {
this.type = type;
this.targetWindow = targetWindow;
- this.callback = callback; // [!code ++]
+ this.callback = callback;
}
public String getType() {
diff --git a/src/main/java/com/axis/innovators/box/browser/WindowOperationHandler.java b/src/main/java/com/axis/innovators/box/browser/WindowOperationHandler.java
index d23115f..bee4c12 100644
--- a/src/main/java/com/axis/innovators/box/browser/WindowOperationHandler.java
+++ b/src/main/java/com/axis/innovators/box/browser/WindowOperationHandler.java
@@ -41,7 +41,7 @@ public class WindowOperationHandler {
return this;
}
- public Builder onOperation(String operation, Consumer handler) {
+ public Builder onOperation(String operation, Consumer handler) {
this.operations.put(operation, handler);
return this;
}
diff --git a/src/main/java/org/tzd/lm/LM.java b/src/main/java/org/tzd/lm/LM.java
index d41cfb2..0ba03b8 100644
--- a/src/main/java/org/tzd/lm/LM.java
+++ b/src/main/java/org/tzd/lm/LM.java
@@ -130,6 +130,44 @@ public class LM {
*/
public static native void llamaFreeContext(long ctxHandle);
+ public static String inference(long modelHandle ,
+ long ctxHandle,
+ float temperature,
+ String prompt,
+ String system,
+ MessageCallback messageCallback, boolean isContinue){
+ //if (isContinue){
+ // return inference(modelHandle,
+ // ctxHandle,
+ // temperature,
+ // 0.1f,
+ // 100,
+ // 0.9f,
+ // 0,
+ // 64,
+ // 1.1f,
+ // 0.0f,
+ // 0.0f,
+ // system + "用户:" + prompt + "\n请继续回答:",
+ // messageCallback
+ // );
+ //}
+ return inference(modelHandle,
+ ctxHandle,
+ temperature,
+ 0.1f,
+ 100,
+ 0.9f,
+ 0,
+ 64,
+ 1.1f,
+ 0.0f,
+ 0.0f,
+ "{问题}" + prompt,
+ messageCallback
+ );
+ }
+
public static String inference(long modelHandle ,
long ctxHandle,
float temperature,
@@ -147,7 +185,7 @@ public class LM {
1.1f,
0.0f,
0.0f,
- system + "\n用户:" + prompt + "\n助手:",
+ system + "\n用户:" + prompt + "\n请开始回答:",
messageCallback
);
}