feature:
1.修改:整合工作模式和闲聊模式。
2.新增:添加交互log。
3.新增:语义完整度相关接口。
4.修改:拆分意图识别服务。
tags/B.2.8.1_20240312_base
| @@ -0,0 +1,21 @@ | |||
| package com.xueyi.nlt.api.nlt.feign; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.nlt.api.nlt.feign.factory.RemoteBaiduNLPFallbackFactory; | |||
| import org.springframework.cloud.openfeign.FeignClient; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestHeader; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| @FeignClient(url = "${notification.baidunlp.url}",name = "baidu-nlp", fallbackFactory = RemoteBaiduNLPFallbackFactory.class) | |||
| public interface RemoteBaiduNLPService { | |||
| @PostMapping(path = "/oauth/2.0/token", consumes = "application/x-www-form-urlencoded") | |||
| JSONObject getAccessToken(@RequestBody String body); | |||
| @PostMapping(path = "/rpc/2.0/nlp/v2/dnnlm_cn", consumes = "application/json") | |||
| JSONObject detected(@RequestParam(value = "charset", defaultValue = "UTF-8") String charset, | |||
| @RequestParam("access_token") String accessToken, | |||
| @RequestBody String body); | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| package com.xueyi.nlt.api.nlt.feign.factory; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteBaiduNLPService; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.springframework.cloud.openfeign.FallbackFactory; | |||
| import org.springframework.stereotype.Component; | |||
| @Slf4j | |||
| @Component | |||
| public class RemoteBaiduNLPFallbackFactory implements FallbackFactory<RemoteBaiduNLPService> { | |||
| @Override | |||
| public RemoteBaiduNLPService create(Throwable cause) { | |||
| return null; | |||
| } | |||
| } | |||
| @@ -2,9 +2,27 @@ package com.xueyi.nlt.netty.server.handler; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| import com.xueyi.common.core.utils.core.ObjectUtil; | |||
| import com.xueyi.common.core.utils.core.SpringUtils; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.DmIntentVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmIntentResponse; | |||
| import com.xueyi.nlt.netty.server.config.ServerConfig; | |||
| import com.xueyi.nlt.nlt.service.IDmIntentService; | |||
| import com.xueyi.nlt.nlt.service.IDmRegularService; | |||
| import com.xueyi.nlt.nlt.service.impl.LogServiceImpl; | |||
| import com.xueyi.nlt.nlt.template.FreeChatTemplate; | |||
| import com.xueyi.nlt.nlt.template.MovieChatTemplate; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteManDeviceService; | |||
| import com.xueyi.system.api.organize.domain.dto.SysEnterpriseDto; | |||
| import com.xueyi.system.api.organize.feign.RemoteEnterpriseService; | |||
| import com.yomahub.tlog.context.TLogContext; | |||
| import com.yomahub.tlog.core.annotation.TLogAspect; | |||
| import com.yomahub.tlog.core.rpc.TLogLabelBean; | |||
| import com.yomahub.tlog.core.rpc.TLogRPCHandler; | |||
| import com.yomahub.tlog.spring.TLogSpringAware; | |||
| import io.netty.channel.Channel; | |||
| import io.netty.channel.ChannelHandlerContext; | |||
| import io.netty.channel.SimpleChannelInboundHandler; | |||
| @@ -24,23 +42,46 @@ import java.time.LocalDateTime; | |||
| public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { | |||
| // 添加log | |||
| private static final Logger log = LoggerFactory.getLogger(ChatServerHandler.class); | |||
| private static final Logger intentLog = LoggerFactory.getLogger("intentLog"); | |||
| public static ChatServerHandler INSTANCE; | |||
| @Autowired | |||
| private RemoteManDeviceService manDeviceService; | |||
| @Autowired | |||
| private FreeChatTemplate freeChatTemplate; | |||
| @Autowired | |||
| private RemoteEnterpriseService remoteEnterpriseService; | |||
| @Autowired | |||
| private IDmIntentService intentService; | |||
| @Autowired | |||
| private MovieChatTemplate movieChatTemplate; | |||
| @Autowired | |||
| private LogServiceImpl logService; | |||
| private final TLogRPCHandler tLogRPCHandler = new TLogRPCHandler(); | |||
| @PostConstruct | |||
| public void init() { | |||
| INSTANCE = this; | |||
| INSTANCE.freeChatTemplate = this.freeChatTemplate; | |||
| INSTANCE.movieChatTemplate = this.movieChatTemplate; | |||
| INSTANCE.intentService = this.intentService; | |||
| INSTANCE.manDeviceService = this.manDeviceService; | |||
| INSTANCE.remoteEnterpriseService = this.remoteEnterpriseService; | |||
| INSTANCE.logService = this.logService; | |||
| } | |||
| @Override | |||
| protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception { | |||
| tLogRPCHandler.processProviderSide(new TLogLabelBean()); | |||
| Channel channel = channelHandlerContext.channel(); | |||
| // 判断textWebSocketFrame.text()是否为空,如果为空,则直接返回 | |||
| if (StringUtils.isEmpty(textWebSocketFrame.text()) || StringUtils.isEmpty(textWebSocketFrame.text().trim()) ) { | |||
| @@ -57,8 +98,27 @@ public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocket | |||
| } | |||
| // 获取到发送人的设备号 | |||
| String devId = jsonObject.getString("devId"); | |||
| Long operatorId = jsonObject.getLong("operatorId"); | |||
| // 获取到发送人的用户id | |||
| String msg = jsonObject.getString("msg"); | |||
| // 判断当前数字人所属租户 | |||
| R<DmManDeviceDto> manDeviceDtoR = INSTANCE.manDeviceService.manDeviceInfoInner(devId); | |||
| if (!manDeviceDtoR.isOk() || manDeviceDtoR.getData() == null) { | |||
| JSONObject jo = new JSONObject(); | |||
| jo.put("action",""); | |||
| jo.put("motion","idle"); | |||
| jo.put("traceId",""); | |||
| jo.put("status",2); | |||
| jo.put("code",1); | |||
| jo.put("tts","设备号未激活或已过期。"); | |||
| channel.writeAndFlush(new TextWebSocketFrame(jo.toJSONString())); | |||
| } | |||
| String enterpriseName = ""; | |||
| // 获取当前数字人租户信息 | |||
| R<SysEnterpriseDto> enterpriseDtoR = INSTANCE.remoteEnterpriseService.getInfo(manDeviceDtoR.getData().getTId()); | |||
| if (enterpriseDtoR.isOk()) { | |||
| enterpriseName = enterpriseDtoR.getData().getName(); | |||
| } | |||
| synchronized (ServerConfig.class) { | |||
| @@ -70,7 +130,36 @@ public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocket | |||
| update(devId, channel); | |||
| } | |||
| try { | |||
| sendMsg(devId, msg); | |||
| DmIntentVo dmIntentVo = new DmIntentVo(); | |||
| dmIntentVo.setContent(msg); | |||
| dmIntentVo.setDevId(devId); | |||
| // 调用正则判断,如果正则匹配到了,则返回正则匹配到的结果 | |||
| DmIntentResponse dmIntentResponse = INSTANCE.intentService.regularAnswer(dmIntentVo); | |||
| if (ObjectUtil.isNotNull(dmIntentResponse) && StringUtils.isNotEmpty(dmIntentResponse.getSkillCode())) { | |||
| JSONObject jo = formatResult(dmIntentResponse,2); | |||
| INSTANCE.reply(channel,msg, jo,enterpriseName,"正则"); | |||
| return; | |||
| } | |||
| // 调用知识库,如果知识库匹配到了,则返回知识库匹配到的结果 | |||
| dmIntentResponse = INSTANCE.intentService.knowledgeAnswer(dmIntentVo); | |||
| if (ObjectUtil.isNotNull(dmIntentResponse) && StringUtils.isNotEmpty(dmIntentResponse.getSkillCode()) && ObjectUtil.isNotNull(dmIntentResponse.getH5()) && dmIntentResponse.getH5().getInteger("accurate") == 1) { | |||
| JSONObject jo = formatResult(dmIntentResponse,2); | |||
| INSTANCE.reply(channel,msg, jo,enterpriseName,"知识库"); | |||
| return; | |||
| } | |||
| else { | |||
| JSONObject jo = new JSONObject(); | |||
| jo.put("action","chat"); | |||
| jo.put("motion","idle"); | |||
| jo.put("traceId",""); | |||
| jo.put("status",0); | |||
| jo.put("tts","请稍等一下,我要查询一下功能。"); | |||
| channel.writeAndFlush(new TextWebSocketFrame(jo.toJSONString())); | |||
| INSTANCE.logService.record(jo,msg,enterpriseName,"大模型"); | |||
| sendMsg(devId, msg); | |||
| } | |||
| } catch (Exception e) { | |||
| JSONObject jo = new JSONObject(); | |||
| jo.put("action","chat"); | |||
| @@ -129,7 +218,9 @@ public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocket | |||
| * @param msg | |||
| * @param userId | |||
| */ | |||
| @TLogAspect(str = "DGMAN-NLT") | |||
| private void sendMsg(String userId, Object msg ) { | |||
| String appName = TLogSpringAware.getProperty("spring.application.name"); | |||
| log.info("设备:{},收到消息:{}", userId,msg); | |||
| Channel channel1 = ServerConfig.sessionMap.get(userId); | |||
| if (channel1 != null) { | |||
| @@ -138,6 +229,22 @@ public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocket | |||
| } | |||
| } | |||
| /** | |||
| * 向客户端发送消息,同时记录日志 | |||
| * | |||
| * @param jo | |||
| * @param enterpriseName | |||
| * @param type | |||
| * | |||
| */ | |||
| @TLogAspect(str = "testtest") | |||
| // @TLogAspect({"enterpriseName","type"}) | |||
| private void reply(Channel channel, String msg, JSONObject jo,String enterpriseName,String type ) { | |||
| INSTANCE.logService.record(jo,msg,enterpriseName,type); | |||
| channel.writeAndFlush(new TextWebSocketFrame(jo.toJSONString())); | |||
| } | |||
| /** | |||
| * 一旦客户端连接上来,该方法被执行 | |||
| * | |||
| @@ -201,4 +308,16 @@ public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocket | |||
| ctx.close(); | |||
| } | |||
| private JSONObject formatResult(DmIntentResponse dmIntentResponse,Integer status) { | |||
| JSONObject resultJson = new JSONObject(); | |||
| resultJson.put("action",dmIntentResponse.getAction()); | |||
| resultJson.put("motion",dmIntentResponse.getMotion()); | |||
| resultJson.put("traceId",""); | |||
| resultJson.put("skillCode",dmIntentResponse.getSkillCode()); | |||
| resultJson.put("status",status); | |||
| resultJson.put("tts",""); | |||
| resultJson.put("h5",dmIntentResponse.getH5()); | |||
| return resultJson; | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| package com.xueyi.nlt.nlt.config; | |||
| import lombok.Data; | |||
| import org.springframework.boot.context.properties.ConfigurationProperties; | |||
| import org.springframework.context.annotation.Configuration; | |||
| @Data | |||
| @Configuration | |||
| @ConfigurationProperties(prefix = "secret.baidu") | |||
| public class BaiduConfig { | |||
| private String apiKey; | |||
| private String secretKey; | |||
| private String authUrl; | |||
| private String dnnUrl; | |||
| } | |||
| @@ -0,0 +1,12 @@ | |||
| package com.xueyi.nlt.nlt.domain.model; | |||
| import com.xueyi.common.core.web.entity.model.BaseConverter; | |||
| import com.xueyi.nlt.nlt.domain.dto.DmRegularDto; | |||
| import com.xueyi.nlt.nlt.domain.po.DmRegularPo; | |||
| import com.xueyi.nlt.nlt.domain.query.DmRegularQuery; | |||
| import org.mapstruct.Mapper; | |||
| import org.mapstruct.MappingConstants; | |||
| @Mapper(componentModel = MappingConstants.ComponentModel.SPRING) | |||
| public interface DmRegularConverter extends BaseConverter<DmRegularQuery, DmRegularDto, DmRegularPo> { | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| package com.xueyi.nlt.nlt.domain.vo; | |||
| import lombok.Data; | |||
| @Data | |||
| public class WordProcessVo{ | |||
| private String metadata; | |||
| private String processedResult; | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| package com.xueyi.nlt.nlt.manager; | |||
| import com.xueyi.common.web.entity.manager.IBaseManager; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmIntentResponse; | |||
| import com.xueyi.nlt.nlt.domain.dto.DmRegularDto; | |||
| import com.xueyi.nlt.nlt.domain.query.DmRegularQuery; | |||
| public interface IDmRegularManager extends IBaseManager<DmRegularQuery, DmRegularDto> { | |||
| public DmIntentResponse doRegularMatch(String content); | |||
| } | |||
| @@ -0,0 +1,41 @@ | |||
| package com.xueyi.nlt.nlt.manager.impl; | |||
| import com.xueyi.common.web.entity.manager.impl.BaseManagerImpl; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmIntentResponse; | |||
| import com.xueyi.nlt.nlt.domain.model.DmRegularConverter; | |||
| import com.xueyi.nlt.nlt.domain.po.DmRegularPo; | |||
| import com.xueyi.nlt.nlt.domain.dto.DmRegularDto; | |||
| import com.xueyi.nlt.nlt.domain.query.DmRegularQuery; | |||
| import com.xueyi.nlt.nlt.manager.IDmRegularManager; | |||
| import com.xueyi.nlt.nlt.mapper.DmRegularMapper; | |||
| import org.springframework.stereotype.Component; | |||
| import java.util.List; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| @Component | |||
| public class DmRegularManager extends BaseManagerImpl<DmRegularQuery, DmRegularDto, DmRegularPo, DmRegularMapper, DmRegularConverter> implements IDmRegularManager { | |||
| @Override | |||
| public DmIntentResponse doRegularMatch(String content) { | |||
| DmIntentResponse response = new DmIntentResponse(); | |||
| List<DmRegularPo> regularPos =baseMapper.selectList(null); | |||
| for (DmRegularPo regularPo : regularPos) { | |||
| if (isMatchRegular(content, regularPo.getExpression())) { | |||
| response.setMsg(regularPo.getText()); | |||
| response.setSkillCode(regularPo.getSkillCode()); | |||
| response.setAction(regularPo.getAction()); | |||
| response.setH5(regularPo.getJson()); | |||
| break; | |||
| } | |||
| } | |||
| return response; | |||
| } | |||
| private boolean isMatchRegular(String str,String regular) { | |||
| Pattern pattern = Pattern.compile(regular); | |||
| Matcher matcher = pattern.matcher(str); | |||
| return matcher.find(); | |||
| } | |||
| } | |||
| @@ -1,8 +1,15 @@ | |||
| package com.xueyi.nlt.nlt.service; | |||
| import com.xueyi.common.web.entity.service.IBaseService; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.DmIntentVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmIntentResponse; | |||
| import com.xueyi.nlt.nlt.domain.dto.DmIntentDto; | |||
| import com.xueyi.nlt.nlt.domain.query.DmIntentQuery; | |||
| public interface IDmIntentService extends IBaseService<DmIntentQuery, DmIntentDto> { | |||
| DmIntentResponse regularAnswer(DmIntentVo intent); | |||
| DmIntentResponse knowledgeAnswer(DmIntentVo intent); | |||
| DmIntentResponse conversation(DmIntentVo intent); | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| package com.xueyi.nlt.nlt.service; | |||
| import com.xueyi.common.web.entity.service.IBaseService; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmIntentResponse; | |||
| import com.xueyi.nlt.nlt.domain.dto.DmRegularDto; | |||
| import com.xueyi.nlt.nlt.domain.query.DmRegularQuery; | |||
| public interface IDmRegularService extends IBaseService<DmRegularQuery, DmRegularDto> { | |||
| DmIntentResponse doRegularMatch(String content); | |||
| } | |||
| @@ -0,0 +1,7 @@ | |||
| package com.xueyi.nlt.nlt.service; | |||
| import com.xueyi.nlt.nlt.domain.vo.WordProcessVo; | |||
| public interface IDmWordProcessService { | |||
| public WordProcessVo semanticIntegrityDetection (WordProcessVo dmWordProcessVo); | |||
| } | |||
| @@ -1,12 +1,312 @@ | |||
| package com.xueyi.nlt.nlt.service.impl; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| import com.xueyi.common.cache.utils.SourceUtil; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.constant.digitalman.MessageConstants; | |||
| import com.xueyi.common.core.constant.digitalman.SkillConstants; | |||
| import com.xueyi.common.core.utils.core.IdUtil; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.common.web.entity.service.impl.BaseServiceImpl; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.CoversationSessionVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.DmIntentVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.KnowledgeVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmIntentResponse; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmKnowledgeResponse; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteQAService; | |||
| import com.xueyi.nlt.nlt.domain.dto.DmIntentDto; | |||
| import com.xueyi.nlt.nlt.domain.query.DmIntentQuery; | |||
| import com.xueyi.nlt.nlt.domain.vo.MarkRecordVo; | |||
| import com.xueyi.nlt.nlt.manager.IDmIntentManager; | |||
| import com.xueyi.nlt.nlt.manager.impl.DmRegularManager; | |||
| import com.xueyi.nlt.nlt.service.IDmIntentService; | |||
| import com.xueyi.nlt.nlt.template.DeliveryOrderTemplate; | |||
| import com.xueyi.nlt.nlt.template.FlightMessageTemplate; | |||
| import com.xueyi.nlt.nlt.template.FreeChatTemplate; | |||
| import com.xueyi.nlt.nlt.template.MeetingOrderTemplate; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmSkillDto; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteManDeviceService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteSkillService; | |||
| import com.xueyi.system.api.model.Source; | |||
| import com.xueyi.system.api.organize.domain.dto.SysEnterpriseDto; | |||
| import com.xueyi.system.api.organize.feign.RemoteEnterpriseService; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.data.redis.core.RedisTemplate; | |||
| import org.springframework.data.redis.core.StringRedisTemplate; | |||
| import org.springframework.stereotype.Service; | |||
| import java.time.LocalDateTime; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| @Service | |||
| public class DmIntentServiceImpl extends BaseServiceImpl<DmIntentQuery, DmIntentDto, IDmIntentManager> implements IDmIntentService { | |||
| private static final Logger log = LoggerFactory.getLogger(DmIntentServiceImpl.class); | |||
| @Autowired | |||
| RemoteEnterpriseService remoteEnterpriseService; | |||
| @Autowired | |||
| private DmRegularManager regularManager; | |||
| @Autowired | |||
| private RemoteManDeviceService manDeviceService; | |||
| @Autowired | |||
| private RemoteQAService remoteQAService; | |||
| @Autowired | |||
| private StringRedisTemplate redisTemplate; | |||
| @Autowired | |||
| private RedisTemplate<Object,Object> redisTemplate2; | |||
| @Autowired | |||
| private MeetingOrderTemplate meetingOrderTemplate; | |||
| @Autowired | |||
| private DeliveryOrderTemplate deliveryOrderTemplate; | |||
| @Autowired | |||
| private FreeChatTemplate freeChatTemplate; | |||
| @Autowired | |||
| private RemoteSkillService remoteskillService; | |||
| @Autowired | |||
| private FlightMessageTemplate flightMessageTemplate; | |||
| @Override | |||
| public DmIntentResponse conversation(DmIntentVo intent) { | |||
| DmIntentResponse response = regularAnswer(intent); | |||
| if (response != null && (StringUtils.isNotEmpty(response.getSkillCode()) || StringUtils.isNotEmpty(response.getMsg()))) { | |||
| return response; | |||
| } | |||
| else{ | |||
| response = knowledgeAnswer(intent); | |||
| } | |||
| if(StringUtils.isEmpty(response.getSkillCode()) && intent.getMode().equals(MessageConstants.MODE_FREE_CHAT)) { | |||
| JSONObject joResult = freeChatTemplate.handle(intent.getDevId(),intent.getContent()); | |||
| response.setH5(joResult); | |||
| } | |||
| return response; | |||
| } | |||
| @Override | |||
| public DmIntentResponse regularAnswer(DmIntentVo intent) { | |||
| MarkRecordVo recordVo = new MarkRecordVo(); | |||
| recordVo.setDevId(intent.getDevId()); | |||
| recordVo.setId(IdUtil.getSnowflakeNextId()); | |||
| recordVo.setCreateTime(LocalDateTime.now()); | |||
| recordVo.setQuestion(intent.getContent()); | |||
| recordVo.setHit(1); | |||
| R<DmManDeviceDto> manDeviceDtoR = manDeviceService.manDeviceInfoInner(intent.getDevId()); | |||
| Long enterpriseId = manDeviceDtoR.getData().getTId(); | |||
| String enterpriseName = ""; | |||
| R<SysEnterpriseDto> enterpriseDtoR = remoteEnterpriseService.getInfo(enterpriseId); | |||
| Source source = SourceUtil.getSourceCache(enterpriseDtoR.getData().getStrategyId()); | |||
| if (enterpriseDtoR.isOk()) { | |||
| enterpriseName = enterpriseDtoR.getData().getName(); | |||
| } | |||
| DmIntentResponse response = sessionHandle(intent); | |||
| //已有session的处理 | |||
| if(response != null && StringUtils.isNotEmpty(response.getSkillCode())){ | |||
| return response; | |||
| } | |||
| // 正则技能匹配 | |||
| response = regularManager.doRegularMatch(intent.getContent()); | |||
| if (response != null && StringUtils.isNotEmpty(response.getSkillCode())){ | |||
| sendToDashboard(intent, enterpriseName); | |||
| // 判断是否有权限 | |||
| R<List<DmSkillDto>> skilllistInner = remoteskillService.skilllistInner(intent.getDevId(),"1",enterpriseId, source.getMaster(), SecurityConstants.INNER); | |||
| if(skilllistInner.isOk()){ | |||
| List<DmSkillDto> skilllist=skilllistInner.getData(); | |||
| for (DmSkillDto dmSkillDto : skilllist) { | |||
| if (dmSkillDto.getSkillCode().equals(response.getSkillCode())) { | |||
| if(dmSkillDto.getStatus().equals("0")){ | |||
| response.clear(); | |||
| response.setMsg("操作无权限"); | |||
| return response; | |||
| } | |||
| // 为技能设置motion | |||
| response.setMotion(dmSkillDto.getMotionName()); | |||
| } | |||
| } | |||
| } | |||
| switch (response.getSkillCode()) { | |||
| case "1": | |||
| // 做会议室处理 | |||
| response.setH5(meetingOrderTemplate.handle(intent.getDevId(), intent.getContent(), enterpriseId)); | |||
| break; | |||
| case "33": | |||
| // 做快递预约处理 | |||
| response.setH5(deliveryOrderTemplate.handle(intent.getDevId(), intent.getContent(), enterpriseId)); | |||
| break; | |||
| case "34": | |||
| // 做查询航班信息处理 | |||
| response.setH5(flightMessageTemplate.handle(intent.getDevId(), intent.getContent(), enterpriseId)); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| }else if(response != null && StringUtils.isNotEmpty(response.getMsg())){ | |||
| // 记录log | |||
| recordVo.setType(2); | |||
| List answers = new ArrayList(); | |||
| answers.add(response.getMsg()); | |||
| recordVo.setAnswers(answers); | |||
| return response; | |||
| } | |||
| return response; | |||
| } | |||
| @Override | |||
| public DmIntentResponse knowledgeAnswer(DmIntentVo intent){ | |||
| MarkRecordVo recordVo = new MarkRecordVo(); | |||
| recordVo.setDevId(intent.getDevId()); | |||
| recordVo.setId(IdUtil.getSnowflakeNextId()); | |||
| recordVo.setCreateTime(LocalDateTime.now()); | |||
| recordVo.setQuestion(intent.getContent()); | |||
| recordVo.setHit(1); | |||
| R<DmManDeviceDto> manDeviceDtoR = manDeviceService.manDeviceInfoInner(intent.getDevId()); | |||
| Long enterpriseId = manDeviceDtoR.getData().getTId(); | |||
| String enterpriseName = ""; | |||
| R<SysEnterpriseDto> enterpriseDtoR = remoteEnterpriseService.getInfo(Long.valueOf(enterpriseId)); | |||
| if (enterpriseDtoR.isOk()) { | |||
| enterpriseName = enterpriseDtoR.getData().getName(); | |||
| } | |||
| // 调用知识库问答 | |||
| DmIntentResponse response = new DmIntentResponse(); | |||
| response.setSkillCode("30"); | |||
| DmKnowledgeResponse qaAjax = null; | |||
| KnowledgeVo knowledgeVo = new KnowledgeVo(); | |||
| knowledgeVo.setManCode(manDeviceDtoR.getData().getManCode()); | |||
| knowledgeVo.setTenantId(manDeviceDtoR.getData().getTId()); | |||
| knowledgeVo.setQuestion(intent.getContent()); | |||
| R<DmKnowledgeResponse> dmKnowledgeResponseR = remoteQAService.query(knowledgeVo); | |||
| if (dmKnowledgeResponseR!= null && dmKnowledgeResponseR.getData() != null) { | |||
| qaAjax = dmKnowledgeResponseR.getData(); | |||
| } | |||
| String content = ""; | |||
| if (qaAjax != null) { | |||
| log.info("知识库问答返回结果:{}",qaAjax.toString()); | |||
| if (qaAjax.getTarget() == 1) { | |||
| content = qaAjax.getResult().get(0).getKnowledgeLib(); | |||
| pushIntoDashboardRedis(enterpriseName,content,"knowledge"); | |||
| response.setH5(JSONObject.from(qaAjax)); | |||
| // 记录log | |||
| recordVo.setType(2); | |||
| List answers = new ArrayList(); | |||
| answers.add(response.getMsg()); | |||
| recordVo.setAnswers(answers); // 航班查询 | |||
| return response; | |||
| } | |||
| else { | |||
| // 知识库没有答案,返回空 | |||
| response.clear(); | |||
| response.setMsg(""); | |||
| } | |||
| } | |||
| return response; | |||
| } | |||
| private DmIntentResponse sessionHandle(DmIntentVo intent) { | |||
| R<DmManDeviceDto> manDeviceDtoR = manDeviceService.manDeviceInfoInner(intent.getDevId()); | |||
| Long enterpriseId = manDeviceDtoR.getData().getTId(); | |||
| DmIntentResponse response = new DmIntentResponse(); | |||
| // 判断会议室缓存 | |||
| // 获取设备号对应缓存 | |||
| //之前已有session信息 | |||
| CoversationSessionVo sessionObject = (CoversationSessionVo) redisTemplate2.opsForValue().get("group:device" + ":" + intent.getDevId() + ":" +"session"); //category | |||
| if (sessionObject != null) { | |||
| switch (sessionObject.getCategory()) { | |||
| case "meeting": | |||
| response.setMsg(""); | |||
| response.setSkillCode("1"); | |||
| response.setH5(meetingOrderTemplate.handle(intent.getDevId(),intent.getContent(), enterpriseId)); | |||
| response.setAction("Meeting"); | |||
| break; | |||
| case "delivery": | |||
| response.setMsg(""); | |||
| response.setSkillCode("33"); | |||
| response.setH5(deliveryOrderTemplate.handle(intent.getDevId(),intent.getContent(), enterpriseId)); | |||
| break; | |||
| case "flight": | |||
| response.setMsg(""); | |||
| response.setSkillCode("34"); | |||
| response.setH5(flightMessageTemplate.handle(intent.getDevId(),intent.getContent(), enterpriseId)); | |||
| break; | |||
| } | |||
| } | |||
| return response; | |||
| } | |||
| private int pushIntoDashboardRedis(String name,String content,String type) { | |||
| try { | |||
| JSONObject object = new JSONObject(); | |||
| object.put("tenantName", name); | |||
| object.put("content", content); | |||
| if (type.equals("skill")) { | |||
| redisTemplate2.opsForList().leftPush("dashboard:skill-consume", object.toJSONString()); | |||
| } else if (type.equals("knowledge")) { | |||
| redisTemplate2.opsForList().leftPush("dashboard:knowledge-consume", object.toJSONString()); | |||
| } | |||
| return 1; | |||
| } catch (Exception e) { | |||
| log.error("推送到仪表盘失败:{}",e.getMessage()); | |||
| return 0; | |||
| } | |||
| } | |||
| private void sendToDashboard(DmIntentVo intent, String enterpriseName) { | |||
| if (SkillConstants.SkillType.BOOK_MEETING_ROOM.getCode().equals(intent.getSkillCode()) ) { | |||
| if (!redisTemplate2.hasKey("group:device" + ":" + intent.getDevId() + ":" +"session")) { | |||
| // 获取名称为"meeting-order"的BaseTemplate的实例 | |||
| redisTemplate.opsForValue().increment("dashboard:meeting", 1); | |||
| pushIntoDashboardRedis(enterpriseName, "会议室预定", "skill"); | |||
| } | |||
| } else if (SkillConstants.SkillType.CREATE_VISITOR_INFO.getCode().equals(intent.getSkillCode())) { | |||
| // 访客预定 | |||
| redisTemplate.opsForValue().increment("dashboard:create_visitor_info", 1); | |||
| pushIntoDashboardRedis(enterpriseName,"访客邀约","skill"); | |||
| } else if (SkillConstants.SkillType.REGISTER_VISITOR.getCode().equals(intent.getSkillCode())) { | |||
| // 访客登记 | |||
| redisTemplate.opsForValue().increment("dashboard:register_visitor", 1); | |||
| pushIntoDashboardRedis(enterpriseName,"陌生人登记","skill"); | |||
| } else if (SkillConstants.SkillType.BROADCAST_DISPLAY.getCode().equals(intent.getSkillCode())) { | |||
| // 播报展示 | |||
| redisTemplate.opsForValue().increment("dashboard:broadcast_display", 1); | |||
| pushIntoDashboardRedis(enterpriseName,"播报展示","skill"); | |||
| } else if (SkillConstants.SkillType.OPEN_DOOR.getCode().equals(intent.getSkillCode())) { | |||
| // 开门记录 | |||
| redisTemplate.opsForValue().increment("dashboard:open_door", 1); | |||
| pushIntoDashboardRedis(enterpriseName,"开门","skill"); | |||
| }else if (SkillConstants.SkillType.DELIVERY.getCode().equals(intent.getSkillCode()) ) { | |||
| if (!redisTemplate2.hasKey("group:device" + ":" + intent.getDevId() + ":" + "session")) { | |||
| // 获取名称为"meeting-order"的BaseTemplate的实例 | |||
| redisTemplate.opsForValue().increment("dashboard:delivery", 1); | |||
| pushIntoDashboardRedis(enterpriseName, "寄快递", "skill"); | |||
| } | |||
| }else if (SkillConstants.SkillType.FLIGHT.getCode().equals(intent.getSkillCode()) ) { | |||
| redisTemplate.opsForValue().increment("dashboard:flight", 1); | |||
| pushIntoDashboardRedis(enterpriseName, "查询航班信息", "skill"); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| package com.xueyi.nlt.nlt.service.impl; | |||
| import com.xueyi.common.web.entity.service.impl.BaseServiceImpl; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.DmIntentVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmIntentResponse; | |||
| import com.xueyi.nlt.nlt.domain.query.DmRegularQuery; | |||
| import com.xueyi.nlt.nlt.domain.dto.DmRegularDto; | |||
| import com.xueyi.nlt.nlt.manager.IDmRegularManager; | |||
| import com.xueyi.nlt.nlt.service.IDmRegularService; | |||
| public class DmRegularServiceImpl extends BaseServiceImpl<DmRegularQuery, DmRegularDto, IDmRegularManager> implements IDmRegularService { | |||
| @Override | |||
| public DmIntentResponse doRegularMatch(String content) { | |||
| return baseManager.doRegularMatch(content); | |||
| } | |||
| } | |||
| @@ -0,0 +1,51 @@ | |||
| package com.xueyi.nlt.nlt.service.impl; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteBaiduNLPService; | |||
| import com.xueyi.nlt.nlt.config.BaiduConfig; | |||
| import com.xueyi.nlt.nlt.domain.vo.WordProcessVo; | |||
| import com.xueyi.nlt.nlt.service.IDmWordProcessService; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Service; | |||
| @Service | |||
| public class DmWordProcessServiceImpl implements IDmWordProcessService { | |||
| @Autowired | |||
| RemoteBaiduNLPService remoteBaiduNLPService; | |||
| @Autowired | |||
| private BaiduConfig baiduConfig; | |||
| private static final Logger log = LoggerFactory.getLogger(DmWordProcessServiceImpl.class); | |||
| public WordProcessVo semanticIntegrityDetection (WordProcessVo wordProcessVo){ | |||
| log.info("元数据:" + wordProcessVo.getMetadata()); | |||
| String body = "grant_type=client_credentials&client_id=" + baiduConfig.getApiKey() + "&client_secret=" + baiduConfig.getSecretKey(); | |||
| JSONObject accessJson = remoteBaiduNLPService.getAccessToken(body); | |||
| JSONObject result = remoteBaiduNLPService.detected("UTF-8", accessJson.getString("access_token"), "{\"text\":\"" + wordProcessVo.getMetadata() + "\"}"); | |||
| if(result.containsKey("ppl")){ | |||
| if(result != null){ | |||
| if(result.containsKey("error_code")){ | |||
| String errorMsg = String.format("语义完整性检测失败,错误码:%d,错误信息:%s", result.getInteger("error_code"),result.getString("error_msg")); | |||
| log.error(errorMsg); | |||
| }else{ | |||
| Double ppl = result.getDouble("ppl"); | |||
| if(ppl < 300) { | |||
| wordProcessVo.setProcessedResult("2"); | |||
| }else if(ppl > 1000){ | |||
| wordProcessVo.setProcessedResult("0"); | |||
| }else{ | |||
| wordProcessVo.setProcessedResult("1"); | |||
| } | |||
| log.info("语义完整性检测结果:" + wordProcessVo.getProcessedResult()); | |||
| } | |||
| }else{ | |||
| log.error("语义完整性检测失败,未获取到返回结果"); | |||
| } | |||
| } | |||
| return wordProcessVo; | |||
| } | |||
| } | |||
| @@ -0,0 +1,19 @@ | |||
| package com.xueyi.nlt.nlt.service.impl; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.yomahub.tlog.core.annotation.TLogAspect; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.stereotype.Component; | |||
| @Component | |||
| public class LogServiceImpl { | |||
| private static final Logger intentLog = LoggerFactory.getLogger("intentLog"); | |||
| @TLogAspect({"enterpriseName","type"}) | |||
| public void record(JSONObject jo,String text,String enterpriseName, String type) { | |||
| jo.put("text",text); | |||
| intentLog.info("{}", jo.toJSONString()); | |||
| } | |||
| } | |||
| @@ -57,11 +57,38 @@ | |||
| </filter> | |||
| </appender> | |||
| <!-- 系统日志输出 --> | |||
| <appender name="file_intent" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||
| <file>${log.path}/intent/intentInfo.log</file> | |||
| <!-- 循环政策:基于时间创建日志文件 --> | |||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||
| <!-- 日志文件名格式 --> | |||
| <fileNamePattern>${log.path}/intent/intentInfo.%d{yyyy-MM-dd}.log</fileNamePattern> | |||
| <!-- 日志最大的历史 60天 --> | |||
| <maxHistory>60</maxHistory> | |||
| </rollingPolicy> | |||
| <encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder"> | |||
| <pattern>${log.pattern}</pattern> | |||
| </encoder> | |||
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |||
| <!-- 过滤的级别 --> | |||
| <level>INFO</level> | |||
| <!-- 匹配时的操作:接收(记录) --> | |||
| <onMatch>ACCEPT</onMatch> | |||
| <!-- 不匹配时的操作:拒绝(不记录) --> | |||
| <onMismatch>DENY</onMismatch> | |||
| </filter> | |||
| </appender> | |||
| <!-- 系统模块日志级别控制 --> | |||
| <logger name="com.xueyi" level="info" /> | |||
| <!-- Spring日志级别控制 --> | |||
| <logger name="org.springframework" level="warn" /> | |||
| <!-- 意图业务日志级别控制 --> | |||
| <logger name="intentLog" additivity="false" level="info" > | |||
| <appender-ref ref="file_intent" /> | |||
| </logger> | |||
| <root level="info"> | |||
| <appender-ref ref="console" /> | |||
| </root> | |||
| @@ -70,5 +97,6 @@ | |||
| <root level="info"> | |||
| <appender-ref ref="file_info" /> | |||
| <appender-ref ref="file_error" /> | |||
| </root> | |||
| </configuration> | |||