AIController.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package com.njuzr.eaibackend.controller;
  2. import com.njuzr.eaibackend.dto.AIDTO;
  3. import com.njuzr.eaibackend.po.AIEntry;
  4. import com.njuzr.eaibackend.service.AIDialogueService;
  5. import com.njuzr.eaibackend.service.AIRequestService;
  6. import com.njuzr.eaibackend.vo.AIDialogueVO;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.data.domain.Page;
  10. import org.springframework.http.MediaType;
  11. import org.springframework.security.access.prepost.PreAuthorize;
  12. import org.springframework.security.core.annotation.AuthenticationPrincipal;
  13. import org.springframework.web.bind.annotation.*;
  14. import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
  15. /**
  16. * @author: Leonezhurui
  17. * @Date: 2024/3/1 - 23:36
  18. * @Package: EAI-Backend
  19. */
  20. @Slf4j
  21. @RestController
  22. @RequestMapping("/api/ai")
  23. public class AIController {
  24. private final AIDialogueService aiDialogueService;
  25. private final AIRequestService aiRequestService;
  26. @Autowired
  27. public AIController(AIDialogueService aiDialogueService, AIRequestService aiRequestService) {
  28. this.aiDialogueService = aiDialogueService;
  29. this.aiRequestService = aiRequestService;
  30. }
  31. @PreAuthorize("hasRole('ROLE_STUDENT') or hasRole('ROLE_TEACHER')")
  32. @GetMapping
  33. public MyResponse getDialogues(
  34. @RequestParam Long assignmentId,
  35. @RequestParam Long userId,
  36. @RequestParam(defaultValue = "0") int page,
  37. @RequestParam(defaultValue = "20") int size
  38. ) {
  39. AIDialogueVO dialogues = aiDialogueService.getAIDialogue(assignmentId, userId, page, size);
  40. return MyResponse.success(dialogues);
  41. }
  42. /**
  43. * 获得AI智能评价的内容(取最后一个即可)
  44. * @return
  45. */
  46. @GetMapping("/rewrite/result")
  47. public MyResponse getRewriteResult(
  48. @RequestParam Long assignmentId,
  49. @RequestParam Long userId
  50. ) {
  51. return MyResponse.success(aiDialogueService.getRewriteResult(assignmentId, userId));
  52. }
  53. /**
  54. * 学生进入写作界面触发,创建AI会话
  55. * @param assignmentId
  56. * @param userId
  57. * @return
  58. */
  59. @PreAuthorize("hasRole('ROLE_STUDENT')")
  60. @PostMapping //这个接口实际上没用过,因为创建会话的操作已经放在了AssignmentController里面的参加作业接口里了
  61. public MyResponse createDialogue(
  62. @RequestParam Long assignmentId,
  63. @AuthenticationPrincipal(expression = "id") Long userId
  64. ) {
  65. aiDialogueService.ensureAIDialogueExists(assignmentId, userId);
  66. return MyResponse.success("创建AI会话成功");
  67. }
  68. /**
  69. * 学生请求AI:1WebClient请求,获得结果;2存储+返回
  70. * @param dialogueId
  71. * @param aidto
  72. * @return
  73. */
  74. @PreAuthorize("hasRole('ROLE_STUDENT')")
  75. @PutMapping
  76. public MyResponse requestAI(
  77. @RequestParam String dialogueId,
  78. @RequestBody AIDTO aidto
  79. ) {
  80. log.info("解析参数为{}, AI会话ID为{}", aidto.toString(), dialogueId);
  81. AIEntry entry = aiDialogueService.requestAI(dialogueId, aidto);
  82. return MyResponse.success(entry);
  83. }
  84. /**
  85. * 学生请求AI(流式响应)- 使用 DeepSeek
  86. * 返回 SSE 流式响应,实时显示AI回复内容
  87. * @param dialogueId 对话ID
  88. * @param aidto 对话请求DTO
  89. * @return SseEmitter 流式响应
  90. */
  91. @PutMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  92. public SseEmitter requestAIStream(
  93. @RequestParam String dialogueId,
  94. @RequestBody(required = false) AIDTO aidto,
  95. @AuthenticationPrincipal(expression = "id") Long principalUserId
  96. ) {
  97. log.info("========== 流式接口被调用 ==========");
  98. log.info("流式对话请求 - dialogueId={}, aidto={}, principalUserId={}", dialogueId, aidto, principalUserId);
  99. if (aidto == null) {
  100. log.error("【错误】请求体为空");
  101. SseEmitter emitter = new SseEmitter();
  102. emitter.completeWithError(new RuntimeException("请求体不能为空"));
  103. return emitter;
  104. }
  105. if (aidto.getMessages() == null) {
  106. log.error("【错误】消息列表为空");
  107. SseEmitter emitter = new SseEmitter();
  108. emitter.completeWithError(new RuntimeException("消息列表不能为空"));
  109. return emitter;
  110. }
  111. if (aidto.getUserId() == null && principalUserId != null) {
  112. aidto.setUserId(principalUserId);
  113. }
  114. log.info("【参数校验通过】dialogueId={}, 消息数={}", dialogueId, aidto.getMessages().size());
  115. try {
  116. SseEmitter result = aiDialogueService.requestAIStream(dialogueId, aidto);
  117. log.info("【成功】调用aiDialogueService.requestAIStream完成");
  118. return result;
  119. } catch (Exception e) {
  120. log.error("【异常】调用aiDialogueService.requestAIStream失败: {}", e.getMessage(), e);
  121. SseEmitter emitter = new SseEmitter();
  122. emitter.completeWithError(e);
  123. return emitter;
  124. }
  125. }
  126. @PostMapping("/rewrite")
  127. public MyResponse rewrite(
  128. @RequestParam Long assignmentId,
  129. @RequestParam Long studentId
  130. ) {
  131. // AIEntry entry = aiDialogueService.rewrite(assignmentId, studentId);
  132. return MyResponse.success(aiDialogueService.rewrite(assignmentId, studentId));
  133. }
  134. @PostMapping("/chatgpt")
  135. public MyResponse requestChatGPT(
  136. @RequestBody AIDTO aidto
  137. ) {
  138. AIRequestService.AIResponse res = aiRequestService.requestChatGPT(aidto.getMessages());
  139. return MyResponse.success(res);
  140. }
  141. }