KBQA问诊代码提交
parent
3cd20c4c4e
commit
b8cd940805
@ -0,0 +1,33 @@
|
|||||||
|
package com.supervision.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class RedisConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||||
|
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||||
|
template.setConnectionFactory(connectionFactory);
|
||||||
|
// 设置 key 和 value 的序列化方式
|
||||||
|
template.setKeySerializer(template.getStringSerializer());
|
||||||
|
|
||||||
|
// 设置 value 的序列化方式为 JSON
|
||||||
|
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||||
|
serializer.setObjectMapper(objectMapper);
|
||||||
|
|
||||||
|
template.setValueSerializer(serializer);
|
||||||
|
template.setHashValueSerializer(serializer);
|
||||||
|
template.afterPropertiesSet();
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.supervision.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public class ItemNotFoundException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常编码
|
||||||
|
*/
|
||||||
|
private final Integer code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常信息
|
||||||
|
*/
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public ItemNotFoundException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
|
||||||
|
this.message = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemNotFoundException(Throwable cause, String message) {
|
||||||
|
super(cause);
|
||||||
|
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
|
||||||
|
this.message = message;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemNotFoundException(String message) {
|
||||||
|
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemNotFoundException(String message, Integer code) {
|
||||||
|
this.message = message;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemNotFoundException(String message, Throwable e) {
|
||||||
|
super(message, e);
|
||||||
|
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.supervision.controller;
|
||||||
|
|
||||||
|
import com.supervision.service.AskService;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.checkerframework.checker.units.qual.C;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("ask")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AskController {
|
||||||
|
|
||||||
|
private final AskService askService;
|
||||||
|
|
||||||
|
@ApiOperation("开启一个文化")
|
||||||
|
@GetMapping("ask")
|
||||||
|
public void ask(String sessionId,String question){
|
||||||
|
askService.ask(sessionId, question);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.supervision.dto.roundAsk;
|
||||||
|
|
||||||
|
import com.supervision.ngbatis.domain.tag.ItemLeaf;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class FindItemNodeResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别到的节点信息
|
||||||
|
*/
|
||||||
|
private String identifyNodeId;
|
||||||
|
|
||||||
|
private String identifyNodeName;
|
||||||
|
|
||||||
|
private String identifyNodeType;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.supervision.dto.roundAsk;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ItemNodeDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过意图识别定位到的节点ID
|
||||||
|
*/
|
||||||
|
private String graphNodeId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过意图识别定位到的图节点名称
|
||||||
|
*/
|
||||||
|
private String graphNodeName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过意图识别定位到的图节点类型
|
||||||
|
*/
|
||||||
|
private String graphNodeType;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.supervision.dto.roundAsk;
|
||||||
|
|
||||||
|
import com.supervision.ngbatis.domain.tag.ItemLeaf;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SessionParamDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始问题
|
||||||
|
*/
|
||||||
|
private String originalQuestion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会话ID
|
||||||
|
*/
|
||||||
|
private String sessionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 意图名称
|
||||||
|
*/
|
||||||
|
private String intent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过实体抽取,抽取到的值
|
||||||
|
*/
|
||||||
|
private String entityValueByExtract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定位到的最终节点
|
||||||
|
*/
|
||||||
|
private ItemLeaf matchItemLeaf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要定位的节点,如果没有唯一节点,就需要从这里开始定位
|
||||||
|
* key 是节点ID
|
||||||
|
* value是节点对象
|
||||||
|
*/
|
||||||
|
private Map<String, ItemLeaf> waitMatchItemLeafMap;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.supervision.handler;
|
package com.supervision.handler.gpt;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
@ -1,4 +1,4 @@
|
|||||||
package com.supervision.handler;
|
package com.supervision.handler.gpt;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.supervision.ai.AiUtil;
|
import com.supervision.ai.AiUtil;
|
@ -0,0 +1,113 @@
|
|||||||
|
package com.supervision.handler.graph;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import com.supervision.ngbatis.dao.CommonQueryDao;
|
||||||
|
import com.supervision.ngbatis.domain.tag.Condition;
|
||||||
|
import com.supervision.ngbatis.domain.tag.ProcessCondition;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jgrapht.Graph;
|
||||||
|
import org.jgrapht.GraphPath;
|
||||||
|
import org.jgrapht.alg.shortestpath.AllDirectedPaths;
|
||||||
|
import org.jgrapht.graph.DefaultEdge;
|
||||||
|
import org.jgrapht.graph.builder.GraphTypeBuilder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 寻找判断节点的链条
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FindConditionPathHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CommonQueryDao commonQueryDao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据某个办理条件节点,寻找所有路径,以用来判断是否符合
|
||||||
|
* @param itemLeafId 叶子节点的ID
|
||||||
|
* @return 所有路径
|
||||||
|
*/
|
||||||
|
public List<List<Condition>> findConditionPath(String itemLeafId) {
|
||||||
|
// 首先根据叶子节点,找到条件节点
|
||||||
|
ProcessCondition conditionVertexByLeafVertex = commonQueryDao.findConditionVertexByLeafVertex(itemLeafId);
|
||||||
|
if (ObjUtil.isEmpty(conditionVertexByLeafVertex)){
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
// 构建一个图,用这个图来找属性结构
|
||||||
|
Graph<Condition, DefaultEdge> jGraph = buildJGraph();
|
||||||
|
// 定位终点的vertexId
|
||||||
|
Set<Condition> finalVertexSet = new HashSet<>();
|
||||||
|
// 从条件节点processConditionVid开始探索下一级节点列表,使用GO语句
|
||||||
|
List<Condition> sourceConditionList = commonQueryDao.findNextConditionByConditionEdge(conditionVertexByLeafVertex.getId());
|
||||||
|
// 如果没有任何绑定的条件节点,
|
||||||
|
if (CollUtil.isEmpty(sourceConditionList)) {
|
||||||
|
// TODO 如果没有任何绑定的条件节点,这里咋整?暂定返回一个空的集合
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
for (Condition sourceVertex : sourceConditionList) {
|
||||||
|
jGraph.addVertex(sourceVertex);
|
||||||
|
}
|
||||||
|
// 下面开始使用递归,开始持续的找下级节点(递归增加次数限制,最多100次)
|
||||||
|
int recursionCount = 0;
|
||||||
|
recursionFindNext(sourceConditionList, jGraph, finalVertexSet, recursionCount);
|
||||||
|
// 根据图去找所有的路径
|
||||||
|
return findAllPath(jGraph, new HashSet<>(sourceConditionList), finalVertexSet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recursionFindNext(List<Condition> sourceIdList, Graph<Condition, DefaultEdge> jGraph, Set<Condition> finalVertexSet, int recursionCount) {
|
||||||
|
// 防止死循环出现无限递归
|
||||||
|
if (recursionCount > 100) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
recursionCount++;
|
||||||
|
for (Condition source : sourceIdList) {
|
||||||
|
List<Condition> nextVertxList = commonQueryDao.findNextConditionByConditionEdge(source.getId());
|
||||||
|
if (CollUtil.isNotEmpty(nextVertxList)) {
|
||||||
|
for (Condition nextVertex : nextVertxList) {
|
||||||
|
jGraph.addVertex(nextVertex);
|
||||||
|
jGraph.addEdge(nextVertex, nextVertex);
|
||||||
|
}
|
||||||
|
recursionFindNext(nextVertxList, jGraph, finalVertexSet, recursionCount);
|
||||||
|
} else {
|
||||||
|
finalVertexSet.add(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Graph<Condition, DefaultEdge> buildJGraph() {
|
||||||
|
// 创建一个树形结构
|
||||||
|
return GraphTypeBuilder
|
||||||
|
.directed()
|
||||||
|
.allowingMultipleEdges(false)
|
||||||
|
.allowingSelfLoops(false)
|
||||||
|
.edgeClass(DefaultEdge.class)
|
||||||
|
.vertexClass(Condition.class)
|
||||||
|
.weighted(false)
|
||||||
|
.buildGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<List<Condition>> findAllPath(Graph<Condition, DefaultEdge> graph, Set<Condition> sourceSet, Set<Condition> targetIdSet) {
|
||||||
|
// 使用深度优先遍历来获取所有路径
|
||||||
|
AllDirectedPaths<Condition, DefaultEdge> directedPaths = new AllDirectedPaths<>(graph);
|
||||||
|
// 根据一个起始点和终止节点,开始找所有的路径
|
||||||
|
List<GraphPath<Condition, DefaultEdge>> allPaths = directedPaths.getAllPaths(sourceSet, targetIdSet, true, 100);
|
||||||
|
// 将所有判断的路径汇聚起来
|
||||||
|
List<List<Condition>> paths = new ArrayList<>();
|
||||||
|
for (GraphPath<Condition, DefaultEdge> path : allPaths) {
|
||||||
|
List<Condition> vertexList = path.getVertexList();
|
||||||
|
if (CollUtil.isNotEmpty(vertexList)) {
|
||||||
|
paths.add(vertexList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.supervision.handler.graph;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.supervision.exception.ItemNotFoundException;
|
||||||
|
import com.supervision.ngbatis.dao.CommonQueryDao;
|
||||||
|
import com.supervision.ngbatis.domain.tag.ItemBranch;
|
||||||
|
import com.supervision.ngbatis.domain.tag.ItemLeaf;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询图数据库,寻找符合条件的节点
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FindItemNodeHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CommonQueryDao commonQueryDao;
|
||||||
|
|
||||||
|
public List<ItemLeaf> findAllMatchLeafNode(String itemName) {
|
||||||
|
log.info("根据事项名称{}寻找可能匹配的节点", itemName);
|
||||||
|
// 首先查询叶子节点的数据,如果有,就直接按照叶子节点的数据来匹配
|
||||||
|
List<ItemLeaf> leafList = commonQueryDao.findItemLeafNodeVertexByItemName(itemName);
|
||||||
|
if (CollUtil.isEmpty(leafList)) {
|
||||||
|
List<ItemBranch> itemBranchNodeVertexByItemName = commonQueryDao.findItemBranchNodeVertexByItemName(itemName);
|
||||||
|
// 如果分支节点不为空,那么就从分支节点去找叶子节点
|
||||||
|
if (CollUtil.isNotEmpty(itemBranchNodeVertexByItemName)) {
|
||||||
|
List<ItemLeaf> leafListTemp = new ArrayList<>();
|
||||||
|
// 遍历分支节点,找到叶子节点
|
||||||
|
for (ItemBranch itemBranch : itemBranchNodeVertexByItemName) {
|
||||||
|
List<ItemLeaf> itemLeafByBranchId = commonQueryDao.findItemLeafByBranchId(itemBranch.getVid());
|
||||||
|
if (CollUtil.isNotEmpty(itemLeafByBranchId)) {
|
||||||
|
leafListTemp.addAll(itemLeafByBranchId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
leafList.addAll(leafListTemp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CollUtil.isEmpty(leafList)) {
|
||||||
|
throw new ItemNotFoundException("未找到与事项匹配的节点");
|
||||||
|
}
|
||||||
|
return leafList;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package com.supervision.ngbatis.dao;
|
||||||
|
|
||||||
|
import com.supervision.ngbatis.domain.tag.Condition;
|
||||||
|
import com.supervision.ngbatis.domain.tag.ItemBranch;
|
||||||
|
import com.supervision.ngbatis.domain.tag.ItemLeaf;
|
||||||
|
import com.supervision.ngbatis.domain.tag.ProcessCondition;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用查询语句
|
||||||
|
*/
|
||||||
|
public interface CommonQueryDao {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据condition_edge边,查找下级路径
|
||||||
|
*
|
||||||
|
* @param vid 开始节点
|
||||||
|
* @return 下级节点列表
|
||||||
|
*/
|
||||||
|
List<String> findNextVertxByConditionEdge(@Param("vid") String vid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据condition_edge边,查找下级路径
|
||||||
|
*
|
||||||
|
* @param vid 开始节点
|
||||||
|
* @return 下级节点列表
|
||||||
|
*/
|
||||||
|
List<Condition> findNextConditionByConditionEdge(@Param("vid") String vid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 找到叶子节点的办理条件
|
||||||
|
*
|
||||||
|
* @param leafVid 叶子结点的ID
|
||||||
|
*/
|
||||||
|
ProcessCondition findConditionVertexByLeafVertex(@Param("leafVid") String leafVid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据属性名称,去找叶子节点
|
||||||
|
*
|
||||||
|
* @param itemName 属性名称,从用户问题中抽取到的事项实体
|
||||||
|
* @return 叶子节点列表
|
||||||
|
*/
|
||||||
|
List<ItemLeaf> findItemLeafNodeVertexByItemName(@Param("itemName") String itemName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据属性名称,去找分支节点
|
||||||
|
*
|
||||||
|
* @param itemName 属性名称,从用户问题中抽取到的事项实体
|
||||||
|
* @return 分支节点列表
|
||||||
|
*/
|
||||||
|
List<ItemBranch> findItemBranchNodeVertexByItemName(@Param("itemName") String itemName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据分支节点,去寻找下面的叶子节点
|
||||||
|
*
|
||||||
|
* @param branchVId 分支节点ID
|
||||||
|
* @return 叶子节点列表
|
||||||
|
*/
|
||||||
|
List<ItemLeaf> findItemLeafByBranchId(@Param("branchVId") String branchVId);
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.supervision.service;
|
||||||
|
|
||||||
|
public interface AskService {
|
||||||
|
|
||||||
|
void ask(String sessionId,String question);
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<mapper namespace="com.supervision.ngbatis.dao.CommonQueryDao">
|
||||||
|
|
||||||
|
<select id="findNextVertxByConditionEdge" resultType="java.lang.String">
|
||||||
|
GO FROM "${vid}" OVER condition_edge YIELD dst(edge);
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="findNextConditionByConditionEdge" resultType="com.supervision.ngbatis.domain.tag.Condition">
|
||||||
|
GO FROM "${vid}" OVER condition_edge YIELD properties($$).entity_type AS entity_type, properties($$).condition AS condition, id($$) AS id;
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="findConditionVertexByLeafVertex" resultType="com.supervision.ngbatis.domain.tag.ProcessCondition">
|
||||||
|
MATCH (b:item_leaf)-[r:process_condition_edge]->(v:process_condition) WHERE id(b) == "${leafVid}" RETURN v;
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="findItemBranchNodeVertexByItemName" resultType="com.supervision.ngbatis.domain.tag.ItemBranch">
|
||||||
|
MATCH (v:item_branch) WHERE v.item_branch.item_name == "${itemName}" RETURN v;
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="findItemLeafNodeVertexByItemName" resultType="com.supervision.ngbatis.domain.tag.ItemLeaf">
|
||||||
|
MATCH (v:item_leaf) WHERE v.item_leaf.item_name == "${itemName}" RETURN v;
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="findItemLeafByBranchId" resultType="com.supervision.ngbatis.domain.tag.ItemLeaf">
|
||||||
|
MATCH (b:item_branch)-[r:dependence_edge*]->(v:item_leaf) WHERE id(b) == "${branchVId}" RETURN DISTINCT v;
|
||||||
|
</select>"
|
||||||
|
</mapper>
|
Loading…
Reference in New Issue