From 9fef8f18ea1ff43566005419731ea90488bfbfe3 Mon Sep 17 00:00:00 2001
From: welsir <1824379011@qq.com>
Date: Thu, 21 Aug 2025 00:07:38 +0800
Subject: [PATCH 1/2] =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E8=81=94=E8=B0=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
prompto-lab-app/pom.xml | 2 +
.../timemachinelab/config/CorsConfig.java | 9 +-
.../controller/UserInteractionController.java | 148 +++-
.../core/question/QuestionParser.java | 7 +-
.../application/ConversationService.java | 91 +--
.../application/MessageProcessingService.java | 41 ++
.../application/SessionManagementService.java | 167 +++++
.../impl/DefaultMessageProcessingService.java | 100 +++
.../domain/entity/ConversationSession.java | 30 +-
.../ai/QuestionGenerationOperation.java | 14 +-
.../web/ConversationController.java | 55 +-
.../web/dto/MessageRequest.java | 12 +-
.../web/dto/MessageResponse.java | 9 +
.../web/dto/UnifiedAnswerRequest.java | 205 ++++++
.../controller/AICallLogController.java | 1 -
.../sfchain/controller/AIModelController.java | 81 +--
.../src/main/resources/application.yml | 2 +-
.../src/components/Chat/AIChatPage.vue | 179 ++---
.../src/services/conversationApi.ts | 114 +--
.../src/services/userInteractionApi.ts | 229 ++++++
prompto-lab-ui/src/views/ApiConfigView.vue | 676 ++++++++++--------
prompto-lab-ui/vite.config.ts | 3 +-
22 files changed, 1568 insertions(+), 607 deletions(-)
create mode 100644 prompto-lab-app/src/main/java/io/github/timemachinelab/core/session/application/MessageProcessingService.java
create mode 100644 prompto-lab-app/src/main/java/io/github/timemachinelab/core/session/application/SessionManagementService.java
create mode 100644 prompto-lab-app/src/main/java/io/github/timemachinelab/core/session/application/impl/DefaultMessageProcessingService.java
create mode 100644 prompto-lab-app/src/main/java/io/github/timemachinelab/core/session/infrastructure/web/dto/UnifiedAnswerRequest.java
create mode 100644 prompto-lab-ui/src/services/userInteractionApi.ts
diff --git a/prompto-lab-app/pom.xml b/prompto-lab-app/pom.xml
index 7581912..6942066 100644
--- a/prompto-lab-app/pom.xml
+++ b/prompto-lab-app/pom.xml
@@ -15,6 +15,8 @@
提示词工程
17
+ 17
+ 17
diff --git a/prompto-lab-app/src/main/java/io/github/timemachinelab/config/CorsConfig.java b/prompto-lab-app/src/main/java/io/github/timemachinelab/config/CorsConfig.java
index 6f93d68..f179e39 100644
--- a/prompto-lab-app/src/main/java/io/github/timemachinelab/config/CorsConfig.java
+++ b/prompto-lab-app/src/main/java/io/github/timemachinelab/config/CorsConfig.java
@@ -27,8 +27,13 @@ public void addCorsMappings(CorsRegistry registry) {
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
- // 允许的源
- configuration.setAllowedOriginPatterns(Arrays.asList("http://localhost:*", "http://127.0.0.1:*"));
+ // 允许的源 - 使用具体的域名模式而不是通配符
+ configuration.setAllowedOriginPatterns(Arrays.asList(
+ "http://localhost:*",
+ "http://127.0.0.1:*",
+ "https://localhost:*",
+ "https://127.0.0.1:*"
+ ));
// 允许的HTTP方法
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
diff --git a/prompto-lab-app/src/main/java/io/github/timemachinelab/controller/UserInteractionController.java b/prompto-lab-app/src/main/java/io/github/timemachinelab/controller/UserInteractionController.java
index a3b2955..6b9bf46 100644
--- a/prompto-lab-app/src/main/java/io/github/timemachinelab/controller/UserInteractionController.java
+++ b/prompto-lab-app/src/main/java/io/github/timemachinelab/controller/UserInteractionController.java
@@ -1,14 +1,26 @@
package io.github.timemachinelab.controller;
+import io.github.timemachinelab.core.session.application.ConversationService;
+import io.github.timemachinelab.core.session.application.MessageProcessingService;
+import io.github.timemachinelab.core.session.application.SessionManagementService;
+import io.github.timemachinelab.core.session.domain.entity.ConversationSession;
+import io.github.timemachinelab.core.session.infrastructure.web.dto.UnifiedAnswerRequest;
+import io.github.timemachinelab.core.session.infrastructure.web.dto.MessageResponse;
import io.github.timemachinelab.entity.req.RetryRequest;
import io.github.timemachinelab.entity.resp.ApiResult;
import io.github.timemachinelab.entity.resp.RetryResponse;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+import javax.annotation.Resource;
import javax.validation.Valid;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* 用户交互控制器
@@ -23,6 +35,52 @@
@Validated
public class UserInteractionController {
+ @Resource
+ private ConversationService conversationService;
+ @Resource
+ private MessageProcessingService messageProcessingService;
+ @Resource
+ private SessionManagementService sessionManagementService;
+ private final Map sseEmitters = new ConcurrentHashMap<>();
+
+ /**
+ * 建立SSE连接
+ */
+ @GetMapping(value = "/sse/{sessionId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+ public SseEmitter streamConversation(@PathVariable String sessionId) {
+ log.info("建立SSE连接 - 会话ID: {}", sessionId);
+
+ SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
+ sseEmitters.put(sessionId, emitter);
+
+ // 连接建立时发送欢迎消息
+ try {
+ emitter.send(SseEmitter.event()
+ .name("connected")
+ .data("SSE连接已建立,会话ID: " + sessionId));
+ } catch (IOException e) {
+ log.error("发送欢迎消息失败: {}", e.getMessage());
+ }
+
+ // 设置连接事件处理
+ emitter.onCompletion(() -> {
+ log.info("SSE连接完成: {}", sessionId);
+ sseEmitters.remove(sessionId);
+ });
+
+ emitter.onTimeout(() -> {
+ log.info("SSE连接超时: {}", sessionId);
+ sseEmitters.remove(sessionId);
+ });
+
+ emitter.onError((ex) -> {
+ log.error("SSE连接错误: {} - {}", sessionId, ex.getMessage());
+ sseEmitters.remove(sessionId);
+ });
+
+ return emitter;
+ }
+
/**
* 重试接口
*
@@ -34,7 +92,9 @@ public ResponseEntity> retry(@Valid @RequestBody RetryR
try {
log.info("收到重试请求 - nodeId: {}, sessionId: {}, whyretry: {}",
request.getNodeId(), request.getSessionId(), request.getWhyretry());
-
+
+
+
// 构建响应数据
RetryResponse response = RetryResponse.builder()
.nodeId(request.getNodeId())
@@ -53,4 +113,90 @@ public ResponseEntity> retry(@Valid @RequestBody RetryR
return ResponseEntity.badRequest().body(ApiResult.serverError("重试请求处理失败: " + e.getMessage()));
}
}
+
+ /**
+ * 处理统一答案请求
+ * 支持单选、多选、输入框、表单等多种问题类型的回答
+ */
+ @PostMapping("/message")
+ public ResponseEntity processAnswer(@Validated @RequestBody UnifiedAnswerRequest request) {
+ try {
+ log.info("接收到答案请求 - 会话ID: {}, 节点ID: {}, 问题类型: {}",
+ request.getSessionId(),
+ request.getNodeId(),
+ request.getQuestionType());
+
+ // 1. 会话管理和验证
+ String userId = request.getUserId();
+
+ ConversationSession session = sessionManagementService.getOrCreateSession(userId, request.getSessionId());
+
+ // 2. 验证nodeId是否属于该会话
+ if (request.getNodeId() != null && !sessionManagementService.validateNodeId(session.getSessionId(), request.getNodeId())) {
+ log.warn("无效的节点ID - 会话: {}, 节点: {}", session.getSessionId(), request.getNodeId());
+ return ResponseEntity.badRequest().body("无效的节点ID");
+ }
+
+ // 3. 验证答案格式
+ if (!messageProcessingService.validateAnswer(request)) {
+ log.warn("答案格式验证失败: {}", request);
+ return ResponseEntity.badRequest().body("答案格式不正确");
+ }
+
+ // 4. 处理答案并转换为消息
+ String processedMessage = messageProcessingService.preprocessMessage(
+ null, // 没有额外的原始消息
+ request,
+ session
+ );
+
+ // 5. 发送处理后的消息给AI服务
+ conversationService.processUserMessage(
+ session.getUserId(),
+ processedMessage,
+ response -> sendSseMessage(session.getSessionId(), response)
+ );
+
+ return ResponseEntity.ok("答案处理成功");
+
+ } catch (Exception e) {
+ log.error("处理答案失败 - 会话ID: {}, 错误: {}", request.getSessionId(), e.getMessage(), e);
+ return ResponseEntity.internalServerError().body("答案处理失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 通过SSE发送消息给客户端
+ *
+ * @param sessionId 会话ID
+ * @param response 消息响应对象
+ */
+ private void sendSseMessage(String sessionId, MessageResponse response) {
+ SseEmitter emitter = sseEmitters.get(sessionId);
+ if (emitter != null) {
+ try {
+ emitter.send(SseEmitter.event()
+ .name("message")
+ .data(response));
+ log.debug("SSE消息发送成功 - 会话: {}, 消息类型: {}", sessionId, response.getType());
+ } catch (IOException e) {
+ log.error("SSE消息发送失败 - 会话: {}, 错误: {}", sessionId, e.getMessage());
+ sseEmitters.remove(sessionId);
+ }
+ } else {
+ log.warn("SSE连接不存在 - 会话: {}", sessionId);
+ }
+ }
+
+ /**
+ * 获取SSE连接状态
+ */
+ @GetMapping("/sse-status")
+ public ResponseEntity