mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/per-boe/java-servers.git
synced 2025-12-06 17:36:47 +08:00
feat: AI消息点赞/踩/取消点赞/取消踩/问题反馈信息保存功能完善
This commit is contained in:
@@ -89,6 +89,7 @@ public class CaseAiChatApi extends ApiBaseController {
|
||||
@PostMapping("/likeMsg")
|
||||
public JsonResponse<Boolean> likeMsg(@RequestBody CaseAiMsgLikeDto caseAiMsgLikeDto) {
|
||||
try {
|
||||
caseAiMsgLikeDto.setOperation(true);
|
||||
if (caseAiChatService.msgFeedback(caseAiMsgLikeDto)) {
|
||||
return success(true, "保存成功");
|
||||
} else {
|
||||
@@ -109,6 +110,7 @@ public class CaseAiChatApi extends ApiBaseController {
|
||||
@PostMapping("/msgFeedback")
|
||||
public JsonResponse<Boolean> msgFeedback(@RequestBody CaseAiMsgLikeDto caseAiMsgLikeDto) {
|
||||
try {
|
||||
caseAiMsgLikeDto.setOperation(false);
|
||||
if (caseAiChatService.msgFeedback(caseAiMsgLikeDto)) {
|
||||
return success(true, "保存成功");
|
||||
} else {
|
||||
|
||||
@@ -21,4 +21,12 @@ public class CaseAiMsgLikeDto {
|
||||
* 反馈
|
||||
*/
|
||||
private String feedback;
|
||||
|
||||
/**
|
||||
* 操作
|
||||
* true: 点踩
|
||||
* false: 反馈
|
||||
* 为空:其他情况
|
||||
*/
|
||||
private Boolean operation;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
|
||||
// 2. 查询历史
|
||||
List<CaseAiMessageVo> historyMessages = elasticSearchIndexService.queryData(conversationId);
|
||||
|
||||
|
||||
// 3. 构建请求参数
|
||||
String userId = currentUser.getCode();
|
||||
|
||||
@@ -165,7 +165,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
}
|
||||
String chatParamStr = chatParam.toJSONString();
|
||||
log.info("案例问答接口请求参数: [{}]", chatParamStr);
|
||||
|
||||
|
||||
// 4. 设置请求头
|
||||
String accessToken;
|
||||
try {
|
||||
@@ -195,7 +195,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
RequestBody bodyRequestBody = RequestBody.create(chatParamStr, MediaType.parse("application/json"));
|
||||
builder.post(bodyRequestBody);
|
||||
Request request = builder.build();
|
||||
|
||||
|
||||
// 7. 创建事件监听器
|
||||
EventSourceListener listener = new EventSourceListener() {
|
||||
@Override
|
||||
@@ -257,14 +257,14 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
@Override
|
||||
public void onEvent(@NotNull EventSource eventSource, @Nullable String id, @Nullable String type, @NotNull String data) {
|
||||
log.info("调用接口 [{}] 监听数据 id: [{}] type: [{}] data: [{}]", request.url(), id, type, data);
|
||||
|
||||
|
||||
try {
|
||||
// 解析返回的数据
|
||||
JSONObject jsonData = JSONObject.parseObject(data);
|
||||
if (jsonData.getBooleanValue("success") && jsonData.getIntValue("code") == 0) {
|
||||
JSONObject responseData = jsonData.getJSONObject("data");
|
||||
Integer status = responseData.getInteger("status");
|
||||
|
||||
|
||||
if (status != null) {
|
||||
CaseAiChatStatusEnum statusEnum = CaseAiChatStatusEnum.getByCode(status);
|
||||
if (statusEnum == CaseAiChatStatusEnum.REFERS) { // 返回引用文件
|
||||
@@ -350,7 +350,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
saveConversationData(conversationData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 8. 执行HTTP请求
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.connectTimeout(60, TimeUnit.SECONDS)
|
||||
@@ -361,16 +361,16 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
.build();
|
||||
EventSource.Factory factory = EventSources.createFactory(client);
|
||||
factory.newEventSource(request, listener);
|
||||
|
||||
|
||||
return sseEmitter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取或创建会话ID
|
||||
*/
|
||||
private String getOrCreateConversationId(CaseAiChatDto caseAiChatDto, CurrentUser currentUser) {
|
||||
String conversationId = caseAiChatDto.getConversationId();
|
||||
|
||||
|
||||
if (StringUtils.isEmpty(conversationId)) {
|
||||
// 新会话,调用创建会话接口
|
||||
String conversationName = "AI案例咨询-" + LocalDateTime.now().toString();
|
||||
@@ -388,39 +388,39 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
String url = caseAiProperties.getBaseUrl() + "/apigateway/knowledge/v1/conversation";
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
|
||||
|
||||
// 设置请求头
|
||||
String accessToken = aiAccessTokenService.getAccessToken();
|
||||
String apiCode = caseAiProperties.getChatApiCode();
|
||||
httpPost.setHeader("access_token", accessToken);
|
||||
httpPost.setHeader("X-AI-ApiCode", apiCode);
|
||||
httpPost.setHeader("Content-Type", "application/json");
|
||||
|
||||
|
||||
// 设置请求体
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("userId", userId);
|
||||
requestBody.put("name", conversationName);
|
||||
StringEntity entity = new StringEntity(requestBody.toJSONString(), StandardCharsets.UTF_8);
|
||||
httpPost.setEntity(entity);
|
||||
|
||||
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
|
||||
|
||||
|
||||
if (statusCode == 200) {
|
||||
JSONObject result = JSONObject.parseObject(responseBody);
|
||||
if (result.getIntValue("code") == 0 && result.getBooleanValue("success")) {
|
||||
JSONObject data = result.getJSONObject("data");
|
||||
String aiConversationId = data.getString("id");
|
||||
String name = data.getString("name");
|
||||
|
||||
|
||||
// 保存到数据库
|
||||
CaseAiConversations conversation = new CaseAiConversations();
|
||||
conversation.setAiConversationId(aiConversationId);
|
||||
conversation.setConversationName(name);
|
||||
conversation.setConversationUser(userId);
|
||||
caseAiConversationsDao.save(conversation);
|
||||
|
||||
|
||||
log.info("创建AI会话成功,aiConversationId: {}, name: {}", aiConversationId, name);
|
||||
return conversation;
|
||||
} else {
|
||||
@@ -503,44 +503,44 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
CaseAiMessageVo messageVo = new CaseAiMessageVo();
|
||||
messageVo.setQuery((String) sourceMap.get("query"));
|
||||
messageVo.setAnswer((String) sourceMap.get("answer"));
|
||||
|
||||
|
||||
// 解析 suggestions
|
||||
Object suggestionsObj = sourceMap.get("suggestions");
|
||||
if (suggestionsObj instanceof List) {
|
||||
messageVo.setSuggestions((List<String>) suggestionsObj);
|
||||
}
|
||||
|
||||
|
||||
// 解析 caseRefer
|
||||
Object caseReferObj = sourceMap.get("caseRefer");
|
||||
if (caseReferObj instanceof List) {
|
||||
List<CaseReferVo> caseReferList = new ArrayList<>();
|
||||
List<Map<String, Object>> caseReferMaps = (List<Map<String, Object>>) caseReferObj;
|
||||
|
||||
|
||||
for (Map<String, Object> caseReferMap : caseReferMaps) {
|
||||
CaseReferVo caseRefer = new CaseReferVo();
|
||||
caseRefer.setCaseId((String) caseReferMap.get("caseId"));
|
||||
caseRefer.setTitle((String) caseReferMap.get("title"));
|
||||
caseRefer.setAuthorName((String) caseReferMap.get("authorName"));
|
||||
caseRefer.setContent((String) caseReferMap.get("content"));
|
||||
|
||||
|
||||
// 解析 keywords
|
||||
Object keywordsObj = caseReferMap.get("keywords");
|
||||
if (keywordsObj instanceof List) {
|
||||
caseRefer.setKeywords((List<String>) keywordsObj);
|
||||
}
|
||||
|
||||
|
||||
caseReferList.add(caseRefer);
|
||||
}
|
||||
messageVo.setCaseRefer(caseReferList);
|
||||
}
|
||||
|
||||
|
||||
return messageVo;
|
||||
} catch (Exception e) {
|
||||
log.error("解析ES消息数据异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理文件引用并构建返给前端的响应数据
|
||||
*/
|
||||
@@ -549,7 +549,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
// 先处理文件引用,收集CaseReferVo数据
|
||||
List<CaseReferVo> currentCaseRefers = new ArrayList<>();
|
||||
Set<String> docIds = new HashSet<>();
|
||||
|
||||
|
||||
JSONObject fileRefer = responseData.getJSONObject("fileRefer");
|
||||
if (fileRefer != null && fileRefer.containsKey("files")) {
|
||||
JSONArray files = fileRefer.getJSONArray("files");
|
||||
@@ -567,13 +567,13 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 构建返给前端的数据结构
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("status", 0);
|
||||
data.put("conversationId", conversationData.getConversationId());
|
||||
data.put("content", responseData.getString("content"));
|
||||
|
||||
|
||||
// 添加处理后的案例引用数据
|
||||
JSONArray caseReferArray = new JSONArray();
|
||||
for (CaseReferVo caseRefer : currentCaseRefers) {
|
||||
@@ -589,11 +589,11 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
|
||||
caseReferArray.add(caseReferObj);
|
||||
}
|
||||
|
||||
|
||||
// 构建新的fileRefer结构,包含案例引用
|
||||
JSONObject newFileRefer = new JSONObject();
|
||||
newFileRefer.put("caseRefers", caseReferArray);
|
||||
|
||||
|
||||
// 保留原始的docs和files信息(如果需要)
|
||||
if (fileRefer != null) {
|
||||
if (fileRefer.containsKey("docs")) {
|
||||
@@ -603,19 +603,19 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
newFileRefer.put("files", fileRefer.get("files"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data.put("fileRefer", newFileRefer);
|
||||
data.put("suggestions", responseData.get("suggestions"));
|
||||
|
||||
|
||||
log.info("处理文件引用成功,返回 {} 个案例引用", currentCaseRefers.size());
|
||||
return data;
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理文件引用并构建响应数据异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理文件引用(原方法,保留用于数据收集)
|
||||
*/
|
||||
@@ -641,7 +641,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
log.error("处理文件引用异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理建议
|
||||
*/
|
||||
@@ -660,7 +660,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
log.error("处理建议异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据docId查询案例引用信息
|
||||
*/
|
||||
@@ -671,7 +671,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
if (docLog == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// 根据 case_id 查询案例详情
|
||||
Cases caseEntity = casesDao.get(docLog.getCaseId());
|
||||
if (caseEntity == null) {
|
||||
@@ -688,7 +688,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
caseRefer.setContent(caseEntity.getSummary());
|
||||
caseRefer.setUploadTime(caseEntity.getSysCreateTime());
|
||||
caseRefer.setOrgInfo(authorOrg.getName());
|
||||
|
||||
|
||||
// 构建关键词列表
|
||||
List<String> keywords = new ArrayList<>();
|
||||
if (caseEntity.getKeyword1() != null) keywords.add(caseEntity.getKeyword1());
|
||||
@@ -697,14 +697,14 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
if (caseEntity.getKeyword4() != null) keywords.add(caseEntity.getKeyword4());
|
||||
if (caseEntity.getKeyword5() != null) keywords.add(caseEntity.getKeyword5());
|
||||
caseRefer.setKeywords(keywords);
|
||||
|
||||
|
||||
return caseRefer;
|
||||
} catch (Exception e) {
|
||||
log.error("根据docId查询案例引用信息异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 当 SSE 失败时,作为普通 HTTP 请求处理
|
||||
* 不再使用
|
||||
@@ -717,12 +717,12 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
.writeTimeout(60, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
|
||||
Response response = client.newCall(request).execute();
|
||||
if (response.isSuccessful()) {
|
||||
String responseBody = response.body().string();
|
||||
log.info("作为普通 HTTP 请求处理成功,将响应原封不动推送给前端");
|
||||
|
||||
|
||||
// 将响应内容原封不动地推送到 SseEmitter
|
||||
JSONObject responseData = JSONObject.parseObject(responseBody);
|
||||
if (responseBody.contains("message")) {
|
||||
@@ -810,9 +810,17 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
log.error("操作失败,docId为空");
|
||||
return false;
|
||||
}
|
||||
if ((StringUtils.equalsAny(caseAiMsgLikeDto.getLikeStatus(), "0", "1", "-1")) || StringUtils.isBlank(caseAiMsgLikeDto.getFeedback())) {
|
||||
log.error("操作失败,参数错误");
|
||||
return false;
|
||||
if (Boolean.TRUE.equals(caseAiMsgLikeDto.getOperation())) {
|
||||
String likeStatus = caseAiMsgLikeDto.getLikeStatus();
|
||||
if (!StringUtils.equals(likeStatus, "1") && !StringUtils.equals(likeStatus, "0") && !StringUtils.equals(likeStatus, "-1")) {
|
||||
log.error("操作失败,参数错误");
|
||||
return false;
|
||||
}
|
||||
} else if (Boolean.FALSE.equals(caseAiMsgLikeDto.getOperation())) {
|
||||
if (StringUtils.isBlank(caseAiMsgLikeDto.getFeedback())) {
|
||||
log.error("操作失败,参数错误");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
aiChatConversationData.setLikeStatus(caseAiMsgLikeDto.getLikeStatus());
|
||||
aiChatConversationData.setFeedback(caseAiMsgLikeDto.getFeedback());
|
||||
|
||||
@@ -11,22 +11,22 @@ spring:
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 192.168.0.253:8848
|
||||
server-addr: 192.168.10.74:8848
|
||||
config:
|
||||
server-addr: 192.168.0.253:8848
|
||||
server-addr: 192.168.10.74:8848
|
||||
redis:
|
||||
database: 1
|
||||
host: 192.168.0.253
|
||||
password: boe@123
|
||||
port: 6379
|
||||
database: 2
|
||||
host: 39.104.123.58
|
||||
password: Ebiz2020
|
||||
port: 6378
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: none
|
||||
datasource:
|
||||
driverClassName: com.mysql.jdbc.Driver
|
||||
url: jdbc:mysql://192.168.0.253:3306/boe_base?useSSL=false&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull
|
||||
username: root
|
||||
password: boe#1234A
|
||||
url: jdbc:mysql://rm-hp3cpkk0u50q90eu9vo.mysql.huhehaote.rds.aliyuncs.com:3306/ebiz_doc_manage?characterEncoding=utf8&useUnicode=true&serverTimezone=Asia/Shanghai&useSSL=false&allowMultiQueries=true
|
||||
username: ebiz_ai
|
||||
password: ebiz_ai123
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
hikari:
|
||||
auto-commit: true
|
||||
@@ -36,7 +36,7 @@ spring:
|
||||
max-lifetime: 1800000
|
||||
maximum-pool-size: 20
|
||||
activemq:
|
||||
broker-url: tcp://192.168.0.253:61616
|
||||
broker-url: tcp://192.168.10.74:61616
|
||||
user: admin
|
||||
password: admin
|
||||
jms:
|
||||
@@ -113,7 +113,7 @@ aop-log-record:
|
||||
#不进行拦截的包或者类
|
||||
excludeClassNames:
|
||||
activemq:
|
||||
broker-url: tcp://192.168.0.253:61616
|
||||
broker-url: tcp://192.168.10.74:61616
|
||||
user: admin
|
||||
password: admin
|
||||
elasticsearch:
|
||||
|
||||
Reference in New Issue
Block a user