@ -1,6 +1,5 @@
package com.supervision.police.service.impl ;
package com.supervision.police.service.impl ;
import cn.hutool.core.util.StrUtil ;
import com.alibaba.druid.util.StringUtils ;
import com.alibaba.druid.util.StringUtils ;
import com.baomidou.mybatisplus.core.conditions.Wrapper ;
import com.baomidou.mybatisplus.core.conditions.Wrapper ;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper ;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper ;
@ -9,19 +8,12 @@ import com.supervision.common.domain.R;
import com.supervision.neo4j.domain.CaseNode ;
import com.supervision.neo4j.domain.CaseNode ;
import com.supervision.neo4j.domain.Rel ;
import com.supervision.neo4j.domain.Rel ;
import com.supervision.neo4j.service.Neo4jService ;
import com.supervision.neo4j.service.Neo4jService ;
import com.supervision.police.domain.ModelRecordType ;
import com.supervision.police.domain.* ;
import com.supervision.police.domain.NoteRecordSplit ;
import com.supervision.police.domain.NotePrompt ;
import com.supervision.police.domain.TripleInfo ;
import com.supervision.police.mapper.ModelRecordTypeMapper ;
import com.supervision.police.mapper.ModelRecordTypeMapper ;
import com.supervision.police.mapper.NoteRecordSplitMapper ;
import com.supervision.police.mapper.NoteRecordSplitMapper ;
import com.supervision.police.mapper.NotePromptMapper ;
import com.supervision.police.service.* ;
import com.supervision.police.mapper.TripleInfoMapper ;
import com.supervision.police.service.ModelRecordTypeService ;
import lombok.RequiredArgsConstructor ;
import lombok.RequiredArgsConstructor ;
import lombok.extern.slf4j.Slf4j ;
import lombok.extern.slf4j.Slf4j ;
import org.json.JSONArray ;
import org.json.JSONObject ;
import org.springframework.ai.chat.ChatResponse ;
import org.springframework.ai.chat.ChatResponse ;
import org.springframework.ai.chat.messages.UserMessage ;
import org.springframework.ai.chat.messages.UserMessage ;
import org.springframework.ai.chat.prompt.Prompt ;
import org.springframework.ai.chat.prompt.Prompt ;
@ -30,8 +22,8 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch ;
import org.springframework.util.StopWatch ;
import java.time.LocalDateTime ;
import java.time.LocalDateTime ;
import java.util.ArrayList ;
import java.util.List ;
import java.util.List ;
import java.util.Optional ;
@Slf4j
@Slf4j
@Service
@Service
@ -42,19 +34,20 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
private final NoteRecordSplitMapper noteRecordSplitMapper ;
private final NoteRecordSplitMapper noteRecordSplitMapper ;
private final NotePrompt Mapper notePromptMapper ;
private final NotePrompt Service notePromptService ;
private final TripleInfo Mapper tripleInfoMapper ;
private final TripleInfo Service tripleInfoService ;
private final Neo4jService neo4jService ;
private final Neo4jService neo4jService ;
private final OllamaChatClient chatClient ;
private final OllamaChatClient chatClient ;
private final CaseTaskRecordService caseTaskRecordService ;
private final ExtractTripleInfoService extractTripleInfo ;
@Override
@Override
public List < ModelRecordType > queryType ( String name , Integer page , Integer size ) {
public List < ModelRecordType > queryType ( String name , Integer page , Integer size ) {
// IPage<ModelRecordType> iPage = new Page<>(page, size);
// iPage = modelRecordTypeMapper.selectByName(iPage, name);
// return R.ok(IPages.buildDataMap(iPage));
List < ModelRecordType > list = modelRecordTypeMapper . selectByName ( name ) ;
List < ModelRecordType > list = modelRecordTypeMapper . selectByName ( name ) ;
for ( ModelRecordType modelRecordType : list ) {
for ( ModelRecordType modelRecordType : list ) {
@ -62,11 +55,10 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
List < NoteRecordSplit > noteRecords = noteRecordSplitMapper . selectByRecordType ( modelRecordType . getRecordType ( ) ) ;
List < NoteRecordSplit > noteRecords = noteRecordSplitMapper . selectByRecordType ( modelRecordType . getRecordType ( ) ) ;
modelRecordType . setRecords ( noteRecords ) ;
modelRecordType . setRecords ( noteRecords ) ;
//提示词
//提示词
List < NotePrompt > prompts = notePrompt Mapper. queryPrompt ( modelRecordType . getId ( ) ) ;
List < NotePrompt > prompts = notePrompt Service. lambdaQuery ( ) . eq ( NotePrompt : : getTypeId , modelRecordType . getId ( ) ) . list ( ) ;
modelRecordType . setPrompts ( prompts ) ;
modelRecordType . setPrompts ( prompts ) ;
}
}
return list ;
return list ;
// return R.ok(IPages.buildDataMap(iPage));
}
}
@Override
@Override
@ -95,12 +87,13 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
@Override
@Override
public R < ? > addOrUpdPrompt ( NotePrompt prompt ) {
public R < ? > addOrUpdPrompt ( NotePrompt prompt ) {
int i = 0 ;
int i = 0 ;
boolean save ;
if ( StringUtils . isEmpty ( prompt . getId ( ) ) ) {
if ( StringUtils . isEmpty ( prompt . getId ( ) ) ) {
i = notePromptMapper . insert ( prompt ) ;
save = notePromptService . save ( prompt ) ;
} else {
} else {
i = notePromptMapper . updateById ( prompt ) ;
save = notePromptService . updateById ( prompt ) ;
}
}
if ( i > 0 ) {
if ( save ) {
return R . ok ( "保存成功" ) ;
return R . ok ( "保存成功" ) ;
} else {
} else {
return R . fail ( "保存失败" ) ;
return R . fail ( "保存失败" ) ;
@ -110,8 +103,8 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
@Override
@Override
public R < ? > delPrompt ( NotePrompt prompt ) {
public R < ? > delPrompt ( NotePrompt prompt ) {
String id = prompt . getId ( ) ;
String id = prompt . getId ( ) ;
int i = notePromptMapper . delet eById( id ) ;
boolean removeById = notePromptService . remov eById( id ) ;
if ( i > 0 ) {
if ( removeById ) {
return R . ok ( "删除成功" ) ;
return R . ok ( "删除成功" ) ;
} else {
} else {
return R . fail ( "删除失败" ) ;
return R . fail ( "删除失败" ) ;
@ -121,8 +114,52 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
@Override
@Override
public List < TripleInfo > getThreeInfo ( String caseId , String name , String recordId ) {
public List < TripleInfo > getThreeInfo ( String caseId , String name , String recordId ) {
// TODO 这里应该改成异步的形式,通过异步的形式来进行提取三元组信息,不能每次点击就跑一遍
boolean taskStatus = taskExtractStatusCheck ( caseId , recordId ) ;
return extractTripleInfo ( caseId , name , recordId ) ;
// 如果校验结果为false,则说明需要进行提取三元组操作
if ( ! taskStatus ) {
extractTripleInfo . extractTripleInfo ( caseId , name , recordId ) ;
}
// 这里进行查询
return tripleInfoService . lambdaQuery ( ) . eq ( TripleInfo : : getRecordId , recordId ) . list ( ) ;
}
/ * *
* 提 取 任 务 校 验 , 校 验 是 否 已 经 存 在 相 关 的 人 物 , 如 果 存 在 相 关 的 任 务 , 就 不 再 继 续 执 行 了 , 直 接 告 诉 任 务 正 在 执 行 中
* /
private boolean taskExtractStatusCheck ( String caseId , String recordId ) {
// 首先查询是否存在任务,如果不存在,就新建
Optional < CaseTaskRecord > caseTaskRecordOpt = caseTaskRecordService . lambdaQuery ( ) . eq ( CaseTaskRecord : : getCaseId , caseId ) . eq ( CaseTaskRecord : : getRecordId , recordId ) . oneOpt ( ) ;
if ( caseTaskRecordOpt . isEmpty ( ) ) {
CaseTaskRecord newCaseTaskRecord = new CaseTaskRecord ( ) ;
newCaseTaskRecord . setCaseId ( caseId ) ;
newCaseTaskRecord . setRecordId ( recordId ) ;
newCaseTaskRecord . setStatus ( 1 ) ;
newCaseTaskRecord . setSubmitTime ( LocalDateTime . now ( ) ) ;
caseTaskRecordService . save ( newCaseTaskRecord ) ;
return false ;
} else {
// 如果存在,则校验时间是否已经超过1天,如果超过了1天还没有执行完毕,就重新提交这个任务
CaseTaskRecord caseTaskRecord = caseTaskRecordOpt . get ( ) ;
if ( caseTaskRecordOpt . get ( ) . getStatus ( ) = = 1 & & LocalDateTime . now ( ) . isAfter ( caseTaskRecord . getSubmitTime ( ) . plusDays ( 1 ) ) ) {
// 如果已经超过1天,则重新提交任务
caseTaskRecord . setStatus ( 1 ) ;
caseTaskRecord . setSubmitTime ( LocalDateTime . now ( ) ) ;
caseTaskRecordService . updateById ( caseTaskRecord ) ;
return false ;
} else if ( caseTaskRecordOpt . get ( ) . getStatus ( ) = = 2 ) {
return true ;
} else if ( caseTaskRecordOpt . get ( ) . getStatus ( ) = = 3 ) {
caseTaskRecord . setStatus ( 1 ) ;
caseTaskRecord . setSubmitTime ( LocalDateTime . now ( ) ) ;
caseTaskRecordService . updateById ( caseTaskRecord ) ;
return false ;
} else {
// 如果没有超过1天,则返回正在执行中
throw new RuntimeException ( "任务正在执行中" ) ;
}
}
}
}
@Override
@Override
@ -152,95 +189,45 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
String content = call . getResult ( ) . getOutput ( ) . getContent ( ) ;
String content = call . getResult ( ) . getOutput ( ) . getContent ( ) ;
log . info ( "分析的结果是:{}" , content ) ;
log . info ( "分析的结果是:{}" , content ) ;
String oldPrompt = "" "
String oldPrompt = "" "
请 分 析 以 下 内 容 中 所 有 规 定 的 三 元 组 信 息 并 补 充 完 整 ,
请 分 析 以 下 内 容 中 所 有 规 定 的 三 元 组 信 息 并 补 充 完 整 ,
要 求 : 1. 返 回 式 :
要 求 : 1. 返 回 式 :
{ result :
{ result :
[
[
{ startNodeType : ' LawActor ' , entity : ' ' , endNodeType : ' FictionalOrgan ' , property : ' ' , value : ' 冒 充 ' } ,
{ startNodeType : ' LawActor ' , entity : ' ' , endNodeType : ' FictionalOrgan ' , property : ' ' , value : ' 冒 充 ' } ,
{ startNodeType : ' LawActor ' , entity : ' ' , endNodeType : ' Seal ' , property : ' ' , value : ' 伪 造 ' } ,
{ startNodeType : ' LawActor ' , entity : ' ' , endNodeType : ' Seal ' , property : ' ' , value : ' 伪 造 ' } ,
{ startNodeType : ' LawActor ' , entity : ' ' , endNodeType : ' BusinessLicense ' , property : ' ' , value : ' 伪 造 ' }
{ startNodeType : ' LawActor ' , entity : ' ' , endNodeType : ' BusinessLicense ' , property : ' ' , value : ' 伪 造 ' }
]
]
} 。
} 。
2. 必 须 考 虑 上 下 文 语 境 分 析 。
2. 必 须 考 虑 上 下 文 语 境 分 析 。
3. 对 话 中 不 包 含 此 类 型 三 元 组 则 返 回 { "result" : [ ] } 。
3. 对 话 中 不 包 含 此 类 型 三 元 组 则 返 回 { "result" : [ ] } 。
例 子 1 : 办 案 警 官 问 : 你 为 了 骗 取 更 多 的 钱 都 做 了 哪 些 准 备 ? 裴 金 禄 回 答 : 我 刚 开 始 我 就 是 自 己 想 了 一 些 关 于 骗 钱 的 点 子 , 后 面 为 了 更 不 容 易 让 别 人 识 破 我 为 了 更 佳 逼 真 , 我 就 从 网 上 随 便 搜 了 一 家 租 赁 公 司 , 我 就 搜 到 了 兰 州 胜 利 机 械 租 赁 有 限 公 司 , 被 讯 问 人 : 裴 金 禄 我 又 想 到 了 我 管 理 的 中 铁 北 京 局 和 中 铁 电 气 化 局 施 工 公 司 。 我 先 是 通 过 百 度 搜 索 了 “ 办 证 ” 之 后 就 在 网 页 上 面 弹 出 了 一 个 页 面 上 面 有 一 个 QQ 号 , 我 就 加 上 了 。 加 上 之 后 我 就 将 我 的 要 求 给 他 说 了 , 要 求 他 给 我 刻 两 个 假 的 公 章 , 一 个 是 兰 州 胜 利 机 械 租 赁 有 限 公 司 合 同 专 用 章 , 另 一 个 是 中 铁 北 京 局 集 团 有 限 公 司 合 同 专 用 章 。 我 还 要 求 他 给 我 伪 造 了 一 张 兰 州 胜 利 机 械 租 赁 有 限 公 司 的 营 业 执 照 。
例 子 1 : 办 案 警 官 问 : 你 为 了 骗 取 更 多 的 钱 都 做 了 哪 些 准 备 ? 裴 金 禄 回 答 : 我 刚 开 始 我 就 是 自 己 想 了 一 些 关 于 骗 钱 的 点 子 , 后 面 为 了 更 不 容 易 让 别 人 识 破 我 为 了 更 佳 逼 真 , 我 就 从 网 上 随 便 搜 了 一 家 租 赁 公 司 , 我 就 搜 到 了 兰 州 胜 利 机 械 租 赁 有 限 公 司 , 被 讯 问 人 : 裴 金 禄 我 又 想 到 了 我 管 理 的 中 铁 北 京 局 和 中 铁 电 气 化 局 施 工 公 司 。 我 先 是 通 过 百 度 搜 索 了 “ 办 证 ” 之 后 就 在 网 页 上 面 弹 出 了 一 个 页 面 上 面 有 一 个 QQ 号 , 我 就 加 上 了 。 加 上 之 后 我 就 将 我 的 要 求 给 他 说 了 , 要 求 他 给 我 刻 两 个 假 的 公 章 , 一 个 是 兰 州 胜 利 机 械 租 赁 有 限 公 司 合 同 专 用 章 , 另 一 个 是 中 铁 北 京 局 集 团 有 限 公 司 合 同 专 用 章 。 我 还 要 求 他 给 我 伪 造 了 一 张 兰 州 胜 利 机 械 租 赁 有 限 公 司 的 营 业 执 照 。
回 答 : { "result" : [ { "startNodeType" : "LawActor" , "entity" : "裴金禄" , "endNodeType" : "FictionalOrgan" , "property" : "兰州胜利机械租赁有限公司" , "value" : "冒充" } , { "startNodeType" : "LawActor" , "entity" : "裴金禄" , "endNodeType" : "Seal" , "property" : "兰州胜利机械租赁有限公司合同专用章" , "value" : "伪造" } , { "startNodeType" : "LawActor" , "entity" : "裴金禄" , "endNodeType" : "Seal" , "property" : "中铁北京局集团有限公司合同专用章" , "value" : "伪造" } , { "startNodeType" : "LawActor" , "entity" : "裴金禄" , "endNodeType" : "BusinessLicense" , "property" : "兰州胜利机械租赁有限公司营业执照" , "value" : "伪造" } ] } 。
回 答 : { "result" : [ { "startNodeType" : "LawActor" , "entity" : "裴金禄" , "endNodeType" : "FictionalOrgan" , "property" : "兰州胜利机械租赁有限公司" , "value" : "冒充" } , { "startNodeType" : "LawActor" , "entity" : "裴金禄" , "endNodeType" : "Seal" , "property" : "兰州胜利机械租赁有限公司合同专用章" , "value" : "伪造" } , { "startNodeType" : "LawActor" , "entity" : "裴金禄" , "endNodeType" : "Seal" , "property" : "中铁北京局集团有限公司合同专用章" , "value" : "伪造" } , { "startNodeType" : "LawActor" , "entity" : "裴金禄" , "endNodeType" : "BusinessLicense" , "property" : "兰州胜利机械租赁有限公司营业执照" , "value" : "伪造" } ] } 。
例 子 2 : 办 案 警 官 问 : 你 为 什 么 要 在 中 卫 市 沙 坡 头 区 签 订 这 些 合 同 ? 裴 金 禄 回 答 : 因 为 我 在 这 边 上 班 , 我 在 中 卫 市 沙 坡 头 区 签 订 合 同 更 能 有 说 服 力 , 这 样 才 能 更 好 地 骗 到 钱 。 回 答 : { "result" : [ ] } 。
例 子 2 : 办 案 警 官 问 : 你 为 什 么 要 在 中 卫 市 沙 坡 头 区 签 订 这 些 合 同 ? 裴 金 禄 回 答 : 因 为 我 在 这 边 上 班 , 我 在 中 卫 市 沙 坡 头 区 签 订 合 同 更 能 有 说 服 力 , 这 样 才 能 更 好 地 骗 到 钱 。 回 答 : { "result" : [ ] } 。
"" " ;
"" " ;
}
}
private List < TripleInfo > extractTripleInfo ( String caseId , String name , String recordId ) {
// 首先获取所有切分后的笔录
List < NoteRecordSplit > recordSplitList = noteRecordSplitMapper . selectRecord ( caseId , name , recordId ) ;
List < TripleInfo > tripleInfos = new ArrayList < > ( ) ;
// 对切分后的笔录进行遍历
for ( NoteRecordSplit record : recordSplitList ) {
// 根据笔录类型找到所有的提取三元组的提示词
List < NotePrompt > prompts = notePromptMapper . queryPrompt ( record . getRecordTypeId ( ) ) ;
// 遍历提示词进行提取
for ( NotePrompt prompt : prompts ) {
if ( StringUtils . isEmpty ( prompt . getPrompt ( ) ) ) {
continue ;
}
try {
StopWatch stopWatch = new StopWatch ( ) ;
// 分析三元组
Prompt ask = new Prompt ( new UserMessage ( prompt . getPrompt ( ) + record . getQuestion ( ) + record . getAnswer ( ) ) ) ;
stopWatch . start ( ) ;
log . info ( "开始分析:" ) ;
ChatResponse call = chatClient . call ( ask ) ;
stopWatch . stop ( ) ;
log . info ( "耗时:{}" , stopWatch . getTotalTimeSeconds ( ) ) ;
String content = call . getResult ( ) . getOutput ( ) . getContent ( ) ;
log . info ( "分析的结果是:{}" , content ) ;
// 获取从提示词中提取到的三元组信息
JSONObject jsonObject = new JSONObject ( content ) ;
JSONArray threeInfo = jsonObject . getJSONArray ( "result" ) ;
for ( int i = 0 ; i < threeInfo . length ( ) ; i + + ) {
JSONObject object = threeInfo . getJSONObject ( i ) ;
String startNodeType = object . getString ( "startNodeType" ) ;
String entity = object . getString ( "entity" ) ;
String endNodeType = object . getString ( "endNodeType" ) ;
String property = object . getString ( "property" ) ;
String value = object . getString ( "value" ) ;
// 去空,如果存在任何的空值,则忽略
if ( StrUtil . hasEmpty ( startNodeType , entity , endNodeType , property , value ) ) {
continue ;
}
// 将三元组信息进行保存操作
TripleInfo tripleInfo = new TripleInfo ( entity , property , value , record . getId ( ) , LocalDateTime . now ( ) , startNodeType , endNodeType ) ;
tripleInfoMapper . insert ( tripleInfo ) ;
tripleInfos . add ( tripleInfo ) ;
}
} catch ( Exception e ) {
log . error ( e . getMessage ( ) , e ) ;
}
}
}
return tripleInfos ;
}
@Override
@Override
public String addNeo4j ( List < String > ids ) {
public String addNeo4j ( List < String > ids ) {
List < TripleInfo > tripleInfos = tripleInfo Mapper. selec tByIds( ids ) ;
List < TripleInfo > tripleInfos = tripleInfoService . listByIds ( ids ) ;
int i = 0 ;
int i = 0 ;
for ( TripleInfo tripleInfo : tripleInfos ) {
for ( TripleInfo tripleInfo : tripleInfos ) {
try {
try {
//开始节点
//开始节点
String start = tripleInfo . getStartNode ( ) ;
String start = tripleInfo . getStartNode ( ) ;
// 首先看是否已经存在了,如果已经存在了,就不添加了
// 首先看是否已经存在了,如果已经存在了,就不添加了
CaseNode startNode = neo4jService . findOneByName ( tripleInfo . getCaseId ( ) , tripleInfo . get Note Records Id( ) , tripleInfo . getStartNodeType ( ) , start , "1" ) ;
CaseNode startNode = neo4jService . findOneByName ( tripleInfo . getCaseId ( ) , tripleInfo . getRecordId ( ) , tripleInfo . getStartNodeType ( ) , start , "1" ) ;
if ( startNode = = null ) {
if ( startNode = = null ) {
startNode = new CaseNode ( start , tripleInfo . getStartNodeType ( ) , tripleInfo . get Note RecordId( ) , tripleInfo . get Note Records Id( ) , tripleInfo . getCaseId ( ) , "1" ) ;
startNode = new CaseNode ( start , tripleInfo . getStartNodeType ( ) , tripleInfo . getRecordSplitId ( ) , tripleInfo . getRecordId ( ) , tripleInfo . getCaseId ( ) , "1" ) ;
CaseNode save = neo4jService . save ( startNode ) ;
CaseNode save = neo4jService . save ( startNode ) ;
startNode . setId ( save . getId ( ) ) ;
startNode . setId ( save . getId ( ) ) ;
}
}
//结束节点
//结束节点
String end = tripleInfo . getEndNode ( ) ;
String end = tripleInfo . getEndNode ( ) ;
CaseNode endNode = neo4jService . findOneByName ( tripleInfo . getCaseId ( ) , tripleInfo . get Note Records Id( ) , tripleInfo . getEndNodeType ( ) , end , "1" ) ;
CaseNode endNode = neo4jService . findOneByName ( tripleInfo . getCaseId ( ) , tripleInfo . getRecordId ( ) , tripleInfo . getEndNodeType ( ) , end , "1" ) ;
if ( endNode = = null ) {
if ( endNode = = null ) {
endNode = new CaseNode ( end , tripleInfo . getEndNodeType ( ) , tripleInfo . get Note RecordId( ) , tripleInfo . get Note Records Id( ) , tripleInfo . getCaseId ( ) , "1" ) ;
endNode = new CaseNode ( end , tripleInfo . getEndNodeType ( ) , tripleInfo . getRecordSplitId ( ) , tripleInfo . getRecordId ( ) , tripleInfo . getCaseId ( ) , "1" ) ;
CaseNode save = neo4jService . save ( endNode ) ;
CaseNode save = neo4jService . save ( endNode ) ;
endNode . setId ( save . getId ( ) ) ;
endNode . setId ( save . getId ( ) ) ;
}
}
@ -251,8 +238,8 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
neo4jService . saveRelation ( rel ) ;
neo4jService . saveRelation ( rel ) ;
}
}
tripleInfo . setAddNeo4j ( "1" ) ;
tripleInfo . setAddNeo4j ( "1" ) ;
int j = tripleInfoMapper . updateById ( tripleInfo ) ;
boolean updateResult = tripleInfoService . updateById ( tripleInfo ) ;
if ( j > 0 ) {
if ( updateResult ) {
i + + ;
i + + ;
}
}
// TODO 重复添加的OK了,删除的呢?
// TODO 重复添加的OK了,删除的呢?