101 lines
4.9 KiB
Java
101 lines
4.9 KiB
Java
1 year ago
|
package com.supervision.service.impl;
|
||
|
|
||
|
import cn.hutool.core.bean.BeanUtil;
|
||
|
import cn.hutool.core.collection.CollUtil;
|
||
|
import cn.hutool.core.util.ObjectUtil;
|
||
|
import cn.hutool.core.util.StrUtil;
|
||
|
import com.supervision.dto.roundAsk.ItemNodeDTO;
|
||
|
import com.supervision.dto.roundAsk.SessionParamDTO;
|
||
|
import com.supervision.handler.gpt.IdentifyIntentHandler;
|
||
|
import com.supervision.handler.gpt.ItemExtractHandler;
|
||
|
import com.supervision.handler.graph.FindConditionPathHandler;
|
||
|
import com.supervision.handler.graph.FindItemNodeHandler;
|
||
|
import com.supervision.ngbatis.domain.tag.Condition;
|
||
|
import com.supervision.ngbatis.domain.tag.ItemLeaf;
|
||
|
import com.supervision.service.AskService;
|
||
|
import lombok.RequiredArgsConstructor;
|
||
|
import lombok.extern.slf4j.Slf4j;
|
||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||
|
import org.springframework.stereotype.Service;
|
||
|
|
||
|
import java.util.*;
|
||
|
import java.util.function.Function;
|
||
|
import java.util.stream.Collectors;
|
||
|
|
||
|
@Slf4j
|
||
|
@Service
|
||
|
@RequiredArgsConstructor
|
||
|
public class AskServiceImpl implements AskService {
|
||
|
|
||
|
private final RedisTemplate<String, Object> redisTemplate;
|
||
|
|
||
|
private final IdentifyIntentHandler identifyIntentHandler;
|
||
|
|
||
|
private final ItemExtractHandler itemExtractHandler;
|
||
|
|
||
|
private final FindItemNodeHandler findItemNodeHandler;
|
||
|
|
||
|
private final FindConditionPathHandler findConditionPathHandler;
|
||
|
|
||
|
private static final String SESSION_PARAM = "KBQA:ASK:SESSION_PARAM:";
|
||
|
|
||
|
|
||
|
@Override
|
||
|
public void ask(String sessionId, String question) {
|
||
|
// 去Redis中,首先判断session处在哪个阶段,是否有识别的意图
|
||
|
Object cache = redisTemplate.opsForValue().get(SESSION_PARAM + sessionId);
|
||
|
SessionParamDTO sessionParamDTO;
|
||
|
if (ObjectUtil.isEmpty(cache)) {
|
||
|
sessionParamDTO = new SessionParamDTO();
|
||
|
sessionParamDTO.setOriginalQuestion(question);
|
||
|
sessionParamDTO.setSessionId(sessionId);
|
||
|
redisTemplate.opsForValue().set(SESSION_PARAM + sessionId, sessionParamDTO);
|
||
|
} else {
|
||
|
sessionParamDTO = BeanUtil.toBean(cache, SessionParamDTO.class);
|
||
|
}
|
||
|
// 判断意图是否为空,如果意图为空,进行识别意图
|
||
|
if (StrUtil.isBlank(sessionParamDTO.getIntent())) {
|
||
|
String intent = identifyIntentHandler.identifyIntent(question);
|
||
|
sessionParamDTO.setIntent(intent);
|
||
|
redisTemplate.opsForValue().set(SESSION_PARAM + sessionId, sessionParamDTO);
|
||
|
}
|
||
|
// 识别出来意图之后,再去判断是否识别过实体
|
||
|
if (StrUtil.isBlank(sessionParamDTO.getEntityValueByExtract())) {
|
||
|
// 识别实体
|
||
|
String extractValue = itemExtractHandler.itemExtract(sessionParamDTO.getOriginalQuestion());
|
||
|
sessionParamDTO.setEntityValueByExtract(extractValue);
|
||
|
// 根据提取的内容,开始在知识图谱中寻找节点(首先找叶子节点,如果叶子节点有数据,直接返回,如果叶子节点没数据,再去找分支节点)
|
||
|
List<ItemLeaf> allMatchLeafNode = findItemNodeHandler.findAllMatchLeafNode(extractValue);
|
||
|
// 如果找到的节点只有1个,那么说明问的就是这个节点,那么直接缓存起来进行下一步
|
||
|
if (allMatchLeafNode.size() == 1) {
|
||
|
ItemLeaf itemLeaf = allMatchLeafNode.get(0);
|
||
|
sessionParamDTO.setMatchItemLeaf(itemLeaf);
|
||
|
redisTemplate.opsForValue().set(SESSION_PARAM + sessionId, sessionParamDTO);
|
||
|
} else {
|
||
|
// 如果不等于1,说明可能有不确定的节点,这时就要开始找节点
|
||
|
Map<String, ItemLeaf> waitMatchItemLeafMap = allMatchLeafNode.stream().collect(Collectors.toMap(ItemLeaf::getVid, Function.identity(), (k1, k2) -> k1));
|
||
|
sessionParamDTO.setWaitMatchItemLeafMap(waitMatchItemLeafMap);
|
||
|
// 开始寻找条件路径
|
||
|
Set<String> itemLeafIdSet = waitMatchItemLeafMap.keySet();
|
||
|
// 所有的实体类型以及出现次数计数
|
||
|
Map<String, Integer> entityCountMap = new HashMap<>();
|
||
|
|
||
|
for (String leafId : itemLeafIdSet) {
|
||
|
List<List<Condition>> conditionPath = findConditionPathHandler.findConditionPath(leafId);
|
||
|
if (CollUtil.isEmpty(conditionPath)) {
|
||
|
waitMatchItemLeafMap.remove(leafId);
|
||
|
} else {
|
||
|
// 如果路径不为空,则放到缓存中去
|
||
|
for (List<Condition> conditions : conditionPath) {
|
||
|
for (Condition condition : conditions) {
|
||
|
// 如果不存在,就添加进计数.如果存在,就+1
|
||
|
entityCountMap.compute(condition.getEntityType(), (k, v) -> v == null ? 1 : v + 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|