Commit 012c8d80 authored by 陈立彬's avatar 陈立彬

AI问答改为流式响应

parent fdb9dd91
......@@ -192,7 +192,10 @@
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
<build>
......
......@@ -2,35 +2,38 @@ package cn.breeze.elleai.application.service;
import cn.breeze.elleai.application.dto.PageResult;
import cn.breeze.elleai.application.dto.inner.AiChatComplateResultDto;
import cn.breeze.elleai.application.dto.inner.AiSingleEvaluateResultDto;
import cn.breeze.elleai.application.dto.request.*;
import cn.breeze.elleai.application.dto.response.*;
import cn.breeze.elleai.domain.sparring.model.request.QaAssistantRequestModel;
import cn.breeze.elleai.domain.sparring.model.request.QaAssistantSaveModel;
import cn.breeze.elleai.domain.sparring.model.request.UserChatCompletionSaveModel;
import cn.breeze.elleai.domain.sparring.model.request.UserQaRequestModel;
import cn.breeze.elleai.domain.sparring.model.response.*;
import cn.breeze.elleai.domain.sparring.model.response.KbTagResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.QaAssistantResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionHistoryResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionResponseModel;
import cn.breeze.elleai.domain.sparring.service.ChatCompletionService;
import cn.breeze.elleai.domain.sparring.service.KbService;
import cn.breeze.elleai.domain.sparring.service.KbTagService;
import cn.breeze.elleai.util.UserPrincipal;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.*;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
......@@ -56,6 +59,17 @@ public class AppChatCompletionService {
private final KbTagService kbTagService;
private WebClient webClient;
@PostConstruct
public void init() {
webClient = WebClient.builder().baseUrl(difyBase)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer "+apiKey)
.defaultHeader(HttpHeaders.CACHE_CONTROL, "no-cache")
.build();
}
/************************************************** AI助手 **************************************************/
......@@ -315,9 +329,7 @@ public class AppChatCompletionService {
* @param request
* @return
*/
public UserAskResultMobileDto userAsk(UserPrincipal userPrincipal, UserQaMobileRequestDto request) {
UserAskResultMobileDto result = new UserAskResultMobileDto();
public Flux<ServerSentEvent<UserAskResultMobileDto>> userAsk(UserPrincipal userPrincipal, UserQaMobileRequestDto request) {
// 获取会话详情
UserQaRequestModel requestModel = new UserQaRequestModel();
requestModel.setChatCompletionId(request.getChatCompletionId());
......@@ -347,29 +359,49 @@ public class AppChatCompletionService {
// 保存问答详情
chatCompletionService.saveUserQaRecord(recordId, 0, request.getContent(), request.getAssistantId());
// 问一下AI
AiChatComplateResultDto complateResultDto = ask4Knowledge(sessionId, userPrincipal.getUserId(), request.getContent(), request.getAssistantId());
if(Objects.nonNull(complateResultDto)) {
String replyContent = complateResultDto.getContent();
// 更新DIFY会话ID
if(StrUtil.isEmpty(sessionId)) {
UserChatCompletionSaveModel updateModel = new UserChatCompletionSaveModel();
updateModel.setId(recordId);
updateModel.setSessionId(sessionId);
chatCompletionService.saveUserQaSession(updateModel);
}
// 保存AI问答详情
chatCompletionService.saveUserQaRecord(recordId, 1, replyContent, request.getAssistantId());
Map<String, String> inputs = new HashMap<>();
inputs.put("assistant_id", Objects.nonNull(request.getAssistantId()) ? String.valueOf(request.getAssistantId()) : "");
JSONObject param = new JSONObject();
param.put("query", request.getContent());
param.put("inputs", inputs);
param.put("response_mode", "streaming");
param.put("conversation_id", sessionId);
param.put("user", userPrincipal.getUserId());
final StringBuffer buffer = new StringBuffer();
final String[] difySessionId = {""};
String finalSessionId = sessionId;
return webClient.post().uri("/chat-messages").accept(MediaType.TEXT_EVENT_STREAM).bodyValue(param.toJSONString()).exchangeToFlux(r -> r.bodyToFlux(String.class))
.mapNotNull(v -> {
JSONObject json = JSONObject.parseObject(v);
String answer = json.getString("answer");
if (ObjectUtil.isNotNull(answer)) {
buffer.append(answer);
}
if(ObjectUtil.isEmpty(difySessionId[0]) && ObjectUtil.isNotEmpty(json.getString("conversation_id"))) {
difySessionId[0] = json.getString("conversation_id");
}
result.setChatCompletionId(recordId);
result.setReplyContent(replyContent);
}
return result;
UserAskResultMobileDto result = new UserAskResultMobileDto();
result.setReplyContent(buffer.toString());
result.setChatCompletionId(recordId);
return result;
}).doOnComplete(
() -> {
String replyContent = buffer.toString();
// 更新DIFY会话ID
if(StrUtil.isEmpty(finalSessionId)) {
UserChatCompletionSaveModel updateModel = new UserChatCompletionSaveModel();
updateModel.setId(recordId);
updateModel.setSessionId(difySessionId[0]);
chatCompletionService.saveUserQaSession(updateModel);
}
// 保存AI问答详情
chatCompletionService.saveUserQaRecord(recordId, 1, replyContent, request.getAssistantId());
}
).map(v -> ServerSentEvent.builder(v).build());
}
/**
* 新会话
* @return
......
......@@ -3,19 +3,25 @@ package cn.breeze.elleai.controller.front;
import cn.breeze.elleai.application.dto.ApiResponse;
import cn.breeze.elleai.application.dto.PageResult;
import cn.breeze.elleai.application.dto.request.*;
import cn.breeze.elleai.application.dto.inner.AiChatComplateResultDto;
import cn.breeze.elleai.application.dto.request.QaAssistantRequestDto;
import cn.breeze.elleai.application.dto.request.SwitchAssistantMobileRequestDto;
import cn.breeze.elleai.application.dto.request.UserQaHistoryRequestDto;
import cn.breeze.elleai.application.dto.request.UserQaMobileRequestDto;
import cn.breeze.elleai.application.dto.response.*;
import cn.breeze.elleai.application.service.AppChatCompletionService;
import cn.breeze.elleai.application.service.AppCommonService;
import cn.breeze.elleai.config.QueryParam;
import cn.breeze.elleai.util.UserPrincipal;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping(value = "/front/chat")
......@@ -51,11 +57,10 @@ public class ChatCompletionMobileController {
@Operation(summary = "用户提问")
@PostMapping("/ask")
public ApiResponse<UserAskResultMobileDto> ask(@Parameter(hidden = true) UserPrincipal userPrincipal,
@RequestBody UserQaMobileRequestDto request) {
public Flux<ServerSentEvent<UserAskResultMobileDto>> ask(@Parameter(hidden = true) UserPrincipal userPrincipal,
@RequestBody UserQaMobileRequestDto request) {
request.setContent(commonService.sentenceWordCorrect(request.getContent()));
UserAskResultMobileDto result = chatCompletionService.userAsk(userPrincipal, request);
return ApiResponse.ok(result);
return chatCompletionService.userAsk(userPrincipal, request);
}
@Operation(summary = "切换助手")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment