From dec3d19f3ce4ef8bf7256a4ad4ca64d22b56b9e4 Mon Sep 17 00:00:00 2001
From: wanghanlin <1533525126@qq.com>
Date: Tue, 30 Jun 2026 14:59:26 +0800
Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=AE=A4=E8=AF=81/=E8=BF=90?=
=?UTF-8?q?=E8=90=A5=E7=9C=8B=E6=9D=BF/API=E5=BC=80=E6=94=BE=E5=B9=B3?=
=?UTF-8?q?=E5=8F=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 25 ++
.../wok/supportbot/SupportBotApplication.java | 4 +
.../com/wok/supportbot/app/AssistantApp.java | 38 ++
.../wok/supportbot/auth/AuthController.java | 162 ++++++++
.../supportbot/config/DatabaseInitConfig.java | 350 ++++++++++++++++-
.../controller/AiModelConfigController.java | 8 +
.../controller/ApiKeyController.java | 183 +++++++++
.../controller/ConversationController.java | 36 +-
.../controller/CustomerAccountController.java | 6 +
.../CustomerServiceRoleController.java | 7 +
.../controller/DashboardController.java | 101 +++++
.../controller/DocumentController.java | 22 ++
.../supportbot/controller/FaqController.java | 14 +-
.../controller/MessageFeedbackController.java | 4 +
.../controller/OpenApiController.java | 149 ++++++++
.../controller/SensitiveWordController.java | 7 +
.../controller/SysRoleController.java | 85 +++++
.../controller/SysUserController.java | 197 ++++++++++
.../controller/WebhookController.java | 190 +++++++++
.../com/wok/supportbot/dao/ApiKeyMapper.java | 12 +
.../dao/DashboardSnapshotMapper.java | 12 +
.../wok/supportbot/dao/RagHitLogMapper.java | 12 +
.../supportbot/dao/SysPermissionMapper.java | 12 +
.../com/wok/supportbot/dao/SysRoleMapper.java | 12 +
.../com/wok/supportbot/dao/SysUserMapper.java | 12 +
.../wok/supportbot/dao/SysUserRoleMapper.java | 12 +
.../supportbot/dao/WebhookConfigMapper.java | 12 +
.../com/wok/supportbot/entity/ApiKey.java | 83 ++++
.../wok/supportbot/entity/ChatMessage.java | 9 +
.../supportbot/entity/DashboardSnapshot.java | 92 +++++
.../wok/supportbot/entity/KnowledgeFaq.java | 9 +-
.../com/wok/supportbot/entity/RagHitLog.java | 66 ++++
.../wok/supportbot/entity/SysPermission.java | 54 +++
.../com/wok/supportbot/entity/SysRole.java | 62 +++
.../com/wok/supportbot/entity/SysUser.java | 83 ++++
.../wok/supportbot/entity/SysUserRole.java | 45 +++
.../wok/supportbot/entity/WebhookConfig.java | 73 ++++
.../supportbot/openapi/ApiKeyAuthFilter.java | 113 ++++++
.../openapi/SlidingWindowRateLimiter.java | 106 +++++
.../supportbot/security/JwtAuthFilter.java | 65 ++++
.../supportbot/security/JwtTokenProvider.java | 108 ++++++
.../supportbot/security/SecurityConfig.java | 115 ++++++
.../wok/supportbot/service/ApiKeyService.java | 170 +++++++++
.../service/ConversationService.java | 16 +-
.../supportbot/service/DashboardService.java | 352 +++++++++++++++++
.../supportbot/service/FaqMatchEngine.java | 4 +-
.../wok/supportbot/service/FaqService.java | 11 +-
.../supportbot/service/RagHitLogService.java | 84 ++++
.../supportbot/service/SysRoleService.java | 73 ++++
.../supportbot/service/SysUserService.java | 270 +++++++++++++
.../supportbot/service/WebhookService.java | 191 +++++++++
src/main/resources/application.yml | 13 +
.../static/components/ApiKeyManager.js | 250 ++++++++++++
.../static/components/DashboardPanel.js | 340 +++++++++++++++++
.../resources/static/components/FaqManager.js | 79 +++-
.../resources/static/components/LoginPage.js | 71 ++++
.../static/components/UserManager.js | 315 +++++++++++++++
.../static/components/WebhookManager.js | 216 +++++++++++
src/main/resources/static/css/main.css | 83 +++-
src/main/resources/static/index.html | 3 +-
src/main/resources/static/js/api.js | 261 ++++++++++++-
src/main/resources/static/js/app.js | 361 ++++++++++++------
src/main/resources/static/js/store.js | 43 ++-
src/main/resources/static/js/utils.js | 55 ++-
64 files changed, 5854 insertions(+), 174 deletions(-)
create mode 100644 src/main/java/com/wok/supportbot/auth/AuthController.java
create mode 100644 src/main/java/com/wok/supportbot/controller/ApiKeyController.java
create mode 100644 src/main/java/com/wok/supportbot/controller/DashboardController.java
create mode 100644 src/main/java/com/wok/supportbot/controller/OpenApiController.java
create mode 100644 src/main/java/com/wok/supportbot/controller/SysRoleController.java
create mode 100644 src/main/java/com/wok/supportbot/controller/SysUserController.java
create mode 100644 src/main/java/com/wok/supportbot/controller/WebhookController.java
create mode 100644 src/main/java/com/wok/supportbot/dao/ApiKeyMapper.java
create mode 100644 src/main/java/com/wok/supportbot/dao/DashboardSnapshotMapper.java
create mode 100644 src/main/java/com/wok/supportbot/dao/RagHitLogMapper.java
create mode 100644 src/main/java/com/wok/supportbot/dao/SysPermissionMapper.java
create mode 100644 src/main/java/com/wok/supportbot/dao/SysRoleMapper.java
create mode 100644 src/main/java/com/wok/supportbot/dao/SysUserMapper.java
create mode 100644 src/main/java/com/wok/supportbot/dao/SysUserRoleMapper.java
create mode 100644 src/main/java/com/wok/supportbot/dao/WebhookConfigMapper.java
create mode 100644 src/main/java/com/wok/supportbot/entity/ApiKey.java
create mode 100644 src/main/java/com/wok/supportbot/entity/DashboardSnapshot.java
create mode 100644 src/main/java/com/wok/supportbot/entity/RagHitLog.java
create mode 100644 src/main/java/com/wok/supportbot/entity/SysPermission.java
create mode 100644 src/main/java/com/wok/supportbot/entity/SysRole.java
create mode 100644 src/main/java/com/wok/supportbot/entity/SysUser.java
create mode 100644 src/main/java/com/wok/supportbot/entity/SysUserRole.java
create mode 100644 src/main/java/com/wok/supportbot/entity/WebhookConfig.java
create mode 100644 src/main/java/com/wok/supportbot/openapi/ApiKeyAuthFilter.java
create mode 100644 src/main/java/com/wok/supportbot/openapi/SlidingWindowRateLimiter.java
create mode 100644 src/main/java/com/wok/supportbot/security/JwtAuthFilter.java
create mode 100644 src/main/java/com/wok/supportbot/security/JwtTokenProvider.java
create mode 100644 src/main/java/com/wok/supportbot/security/SecurityConfig.java
create mode 100644 src/main/java/com/wok/supportbot/service/ApiKeyService.java
create mode 100644 src/main/java/com/wok/supportbot/service/DashboardService.java
create mode 100644 src/main/java/com/wok/supportbot/service/RagHitLogService.java
create mode 100644 src/main/java/com/wok/supportbot/service/SysRoleService.java
create mode 100644 src/main/java/com/wok/supportbot/service/SysUserService.java
create mode 100644 src/main/java/com/wok/supportbot/service/WebhookService.java
create mode 100644 src/main/resources/static/components/ApiKeyManager.js
create mode 100644 src/main/resources/static/components/DashboardPanel.js
create mode 100644 src/main/resources/static/components/LoginPage.js
create mode 100644 src/main/resources/static/components/UserManager.js
create mode 100644 src/main/resources/static/components/WebhookManager.js
diff --git a/pom.xml b/pom.xml
index 177ffa0..97bfe89 100644
--- a/pom.xml
+++ b/pom.xml
@@ -150,6 +150,31 @@
org.springframework.ai
spring-ai-tika-document-reader
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.12.6
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.12.6
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.12.6
+ runtime
+
+
org.springframework.security
diff --git a/src/main/java/com/wok/supportbot/SupportBotApplication.java b/src/main/java/com/wok/supportbot/SupportBotApplication.java
index 87771ef..aab707c 100644
--- a/src/main/java/com/wok/supportbot/SupportBotApplication.java
+++ b/src/main/java/com/wok/supportbot/SupportBotApplication.java
@@ -2,6 +2,8 @@ package com.wok.supportbot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 主启动类
@@ -9,6 +11,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* 确保 ToolCallingAutoConfiguration 不会抛出 ClassNotFoundException
*/
@SpringBootApplication
+@EnableScheduling
+@EnableAsync
public class SupportBotApplication {
public static void main(String[] args) {
diff --git a/src/main/java/com/wok/supportbot/app/AssistantApp.java b/src/main/java/com/wok/supportbot/app/AssistantApp.java
index 0b2e505..0e8b11a 100644
--- a/src/main/java/com/wok/supportbot/app/AssistantApp.java
+++ b/src/main/java/com/wok/supportbot/app/AssistantApp.java
@@ -9,6 +9,7 @@ import com.wok.supportbot.rag.preretrieval.CompressionQueryRewriter;
import com.wok.supportbot.rag.preretrieval.MultiQueryExpanderRewriter;
import com.wok.supportbot.rag.preretrieval.RewriteQueryRewriter;
import com.wok.supportbot.rag.preretrieval.TranslationQueryRewriter;
+import com.wok.supportbot.service.FaqMatchEngine;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
@@ -38,6 +39,7 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -60,6 +62,9 @@ public class AssistantApp {
@Resource
private ContentSafetyAdvisor contentSafetyAdvisor;
+ @Resource
+ private FaqMatchEngine faqMatchEngine;
+
private final ChatModelFactory chatModelFactory;
private final DatabaseChatMemory chatMemory;
@@ -170,6 +175,25 @@ public class AssistantApp {
return spec.stream().content();
}
+ // ==================== FAQ 优先匹配 ====================
+
+ /**
+ * 尝试 FAQ 三级匹配(精确→关键词→语义),命中则返回标准答案。
+ * 在 RAG 对话入口处优先调用,避免不必要的知识库检索开销。
+ *
+ * @param message 用户消息
+ * @return FAQ 标准答案(未命中时返回 empty)
+ */
+ private Optional tryFaqMatch(String message) {
+ try {
+ return faqMatchEngine.match(message)
+ .map(result -> result.getFaq().getAnswer());
+ } catch (Exception e) {
+ log.warn("FAQ 匹配异常,降级到 RAG: {}", e.getMessage());
+ return Optional.empty();
+ }
+ }
+
// AI 恋爱知识库问答功能
@Resource
RewriteQueryRewriter rewriteQueryRewriter;
@@ -226,6 +250,13 @@ public class AssistantApp {
}
public String doChatWithRagStrategy(String message, String chatId, String strategy, List categoryIds, String systemPrompt) {
+ // FAQ 优先匹配:三级匹配(精确→关键词→语义)命中则直接返回标准答案
+ Optional faqAnswer = tryFaqMatch(message);
+ if (faqAnswer.isPresent()) {
+ log.info("FAQ 命中,直接返回标准答案: chatId={}", chatId);
+ return faqAnswer.get();
+ }
+
// 对于 MULTI_QUERY 策略,需要使用特殊的处理方式
if ("MULTI_QUERY".equalsIgnoreCase(strategy)) {
return doChatWithMultiQueryRag(message, chatId, categoryIds, systemPrompt);
@@ -282,6 +313,13 @@ public class AssistantApp {
*/
public Flux doChatWithRagStrategyByStream(String message, String chatId, String strategy,
List categoryIds, String systemPrompt) {
+ // FAQ 优先匹配:命中则直接以流式形式返回标准答案
+ Optional faqAnswer = tryFaqMatch(message);
+ if (faqAnswer.isPresent()) {
+ log.info("FAQ 命中(流式),直接返回标准答案: chatId={}", chatId);
+ return Flux.just(faqAnswer.get());
+ }
+
// 对于 MULTI_QUERY 策略,需要先手动检索合并再流式生成
if ("MULTI_QUERY".equalsIgnoreCase(strategy)) {
return doChatWithMultiQueryRagByStream(message, chatId, categoryIds, systemPrompt);
diff --git a/src/main/java/com/wok/supportbot/auth/AuthController.java b/src/main/java/com/wok/supportbot/auth/AuthController.java
new file mode 100644
index 0000000..3399d9e
--- /dev/null
+++ b/src/main/java/com/wok/supportbot/auth/AuthController.java
@@ -0,0 +1,162 @@
+package com.wok.supportbot.auth;
+
+import com.wok.supportbot.entity.SysRole;
+import com.wok.supportbot.entity.SysUser;
+import com.wok.supportbot.security.JwtTokenProvider;
+import com.wok.supportbot.service.SysUserService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 认证控制器
+ * 处理登录、Token 刷新、当前用户信息查询
+ */
+@Slf4j
+@RestController
+@RequestMapping("/auth")
+public class AuthController {
+
+ private final AuthenticationManager authenticationManager;
+ private final JwtTokenProvider jwtTokenProvider;
+ private final SysUserService sysUserService;
+
+ public AuthController(AuthenticationManager authenticationManager,
+ JwtTokenProvider jwtTokenProvider,
+ SysUserService sysUserService) {
+ this.authenticationManager = authenticationManager;
+ this.jwtTokenProvider = jwtTokenProvider;
+ this.sysUserService = sysUserService;
+ }
+
+ /**
+ * 用户登录
+ */
+ @PostMapping("/login")
+ public ResponseEntity