diff --git a/backend/src/main/java/com/zl/mjga/config/ai/DeepSeekConfiguration.java b/backend/src/main/java/com/zl/mjga/config/ai/DeepSeekConfiguration.java
index 02b8b74..f1d58c3 100644
--- a/backend/src/main/java/com/zl/mjga/config/ai/DeepSeekConfiguration.java
+++ b/backend/src/main/java/com/zl/mjga/config/ai/DeepSeekConfiguration.java
@@ -1,14 +1,25 @@
package com.zl.mjga.config.ai;
+import jakarta.annotation.PostConstruct;
import lombok.Data;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
@Data
@Component
@ConfigurationProperties(prefix = "deep-seek")
public class DeepSeekConfiguration {
+ @jakarta.annotation.Resource
+ private ResourceLoader resourceLoader;
+
private String baseUrl;
private String apiKey;
private Prompt prompt;
@@ -18,4 +29,12 @@ public class DeepSeekConfiguration {
public static class Prompt {
private String system;
}
+
+ @PostConstruct
+ public void init() throws IOException {
+ Resource resource = resourceLoader.getResource("classpath:prompt.txt");
+ prompt = new Prompt();
+ prompt.setSystem(Files.readString(Paths.get(resource.getURI())));
+ }
}
+
diff --git a/backend/src/main/java/com/zl/mjga/controller/AiController.java b/backend/src/main/java/com/zl/mjga/controller/AiController.java
index e137ce1..e554731 100644
--- a/backend/src/main/java/com/zl/mjga/controller/AiController.java
+++ b/backend/src/main/java/com/zl/mjga/controller/AiController.java
@@ -8,7 +8,6 @@ import java.time.Duration;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
-import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;
@@ -34,8 +33,6 @@ public class AiController {
.onError(sink::tryEmitError)
.start();
return sink.asFlux()
- .timeout(Duration.ofSeconds(120))
- .doOnCancel(SecurityContextHolder::clearContext)
- .doOnTerminate(SecurityContextHolder::clearContext);
+ .timeout(Duration.ofSeconds(120));
}
}
diff --git a/backend/src/main/resources/ai.yml b/backend/src/main/resources/ai.yml
index 368bc8a..af6a6cf 100644
--- a/backend/src/main/resources/ai.yml
+++ b/backend/src/main/resources/ai.yml
@@ -1,6 +1,4 @@
deep-seek:
base-url: "https://api.deepseek.com"
api-key: "sk-3633b0cd40884b27aa8402a1c5dc029d"
- model-name: "deepseek-chat"
- prompt:
- system: "你是一个名叫「知路智能体」的企业级AI助手,能帮助用户解决各种问题。"
+ model-name: "deepseek-chat"
\ No newline at end of file
diff --git a/backend/src/main/resources/prompt.txt b/backend/src/main/resources/prompt.txt
new file mode 100644
index 0000000..fa059ed
--- /dev/null
+++ b/backend/src/main/resources/prompt.txt
@@ -0,0 +1 @@
+你是一个名为「知路智能体」的企业级AI助手,严格遵循使用Markdown格式来回复内容。
\ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 9328407..07fc07c 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -13,7 +13,9 @@
"@vueuse/core": "^13.0.0",
"apexcharts": "^3.46.0",
"dayjs": "^1.11.13",
+ "dompurify": "^3.2.6",
"flowbite": "^3.1.2",
+ "marked": "^15.0.12",
"openapi-fetch": "^0.13.5",
"pinia": "^3.0.1",
"tailwindcss": "^4.0.14",
@@ -26,6 +28,8 @@
"@faker-js/faker": "^9.6.0",
"@playwright/test": "^1.51.0",
"@tsconfig/node22": "^22.0.0",
+ "@types/dompurify": "^3.0.5",
+ "@types/marked": "^5.0.2",
"@types/node": "^22.13.9",
"@vitejs/plugin-vue": "^5.2.1",
"@vitest/browser": "^3.0.9",
@@ -2127,12 +2131,29 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/dompurify": {
+ "version": "3.0.5",
+ "resolved": "http://mirrors.tencent.com/npm/@types/dompurify/-/dompurify-3.0.5.tgz",
+ "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/trusted-types": "*"
+ }
+ },
"node_modules/@types/estree": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"license": "MIT"
},
+ "node_modules/@types/marked": {
+ "version": "5.0.2",
+ "resolved": "http://mirrors.tencent.com/npm/@types/marked/-/marked-5.0.2.tgz",
+ "integrity": "sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/node": {
"version": "22.15.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz",
@@ -2163,6 +2184,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "http://mirrors.tencent.com/npm/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/@types/web-bluetooth": {
"version": "0.0.21",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
@@ -3327,6 +3355,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/dompurify": {
+ "version": "3.2.6",
+ "resolved": "http://mirrors.tencent.com/npm/dompurify/-/dompurify-3.2.6.tgz",
+ "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
+ },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -4424,6 +4461,18 @@
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
+ "node_modules/marked": {
+ "version": "15.0.12",
+ "resolved": "http://mirrors.tencent.com/npm/marked/-/marked-15.0.12.tgz",
+ "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==",
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index f98c958..7ca8526 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -23,7 +23,9 @@
"@vueuse/core": "^13.0.0",
"apexcharts": "^3.46.0",
"dayjs": "^1.11.13",
+ "dompurify": "^3.2.6",
"flowbite": "^3.1.2",
+ "marked": "^15.0.12",
"openapi-fetch": "^0.13.5",
"pinia": "^3.0.1",
"tailwindcss": "^4.0.14",
@@ -36,6 +38,8 @@
"@faker-js/faker": "^9.6.0",
"@playwright/test": "^1.51.0",
"@tsconfig/node22": "^22.0.0",
+ "@types/dompurify": "^3.0.5",
+ "@types/marked": "^5.0.2",
"@types/node": "^22.13.9",
"@vitejs/plugin-vue": "^5.2.1",
"@vitest/browser": "^3.0.9",
@@ -52,6 +56,8 @@
"vue-tsc": "^2.2.8"
},
"msw": {
- "workerDirectory": ["public"]
+ "workerDirectory": [
+ "public"
+ ]
}
}
diff --git a/frontend/src/views/AiChatView.vue b/frontend/src/views/AiChatView.vue
index 37ca504..a9ebdfd 100644
--- a/frontend/src/views/AiChatView.vue
+++ b/frontend/src/views/AiChatView.vue
@@ -11,9 +11,9 @@
- {{ chatElement.content }} -
+