[长文本方案]

jinan_dev
longbao
parent 00f85c8dc9
commit 95b5736221

@ -0,0 +1,96 @@
package com.supervision.constant;
import lombok.Getter;
/**
* @Authorlongbao
* @Date2024/12/10 13:37
* @Description:
*/
@Getter
public enum PromptsEnum {
LONG_TEXT_SINGLE_SENTENCE_SUMMARY("长文本单句总结提示词", """
: 2
:
: (1)
---
:
1 2
:{"result": {"id": "1","llmGenA":"冒充"},{"id": "2","llmGenA":"欺诈"}}
---
:
1.
2. 2
3.
4.
5. idllmGenA
6.
7.
---
:
{noteRecordSplitList}
---
json,:{"result": [{"id": "","llmGenA":""}]}
"""),
LONG_TEXT_SINGLE_STATEMENT_WITH_SEMANTIC_JUDGMENT_PROMPT_WORD("长文本单语句同语义判断提示词", """
:
:
:
---
:
{"result":false}
---
1.
3.
4.
5. truefalse
6. 2
---
:
{encCombinedSentence}
{currentSentence}
---
json:
{"result":xxxx}
"""),
LONG_TEXT_TRIPLE_INFO("长文本三元组信息提取", """
:
1.
2.
3.
4.
5. 使
6.
{requirement}
"{headEntityType}";"{tailEntityType}","{relation}"
json:{"result":[]}
---
:
{"result":[{"headEntity": {"type": "{headEntityType}","name":"小明"},"relation": "{relation}","tailEntity": {"type": "{tailEntityType}","name": "光缆承揽合同"}}]}
---
{contentChuckSummary}
---
json:
{"result":[{"headEntity": {"type": "{headEntityType}","name":"提取到的头实体内容1"},"relation": "{relation}","tailEntity": {"type": "{tailEntityType}","name": "提取到的尾实体内容1"}}]}
""");
private String description;
private String content;
PromptsEnum(String description, String content) {
this.description = description;
this.content = content;
}
}

@ -0,0 +1,27 @@
package com.supervision.handler;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;
public class StringListTypeHandler extends JacksonTypeHandler {
private static final ObjectMapper objectMapper = new ObjectMapper();
public StringListTypeHandler(Class<Object> type) {
super(type);
}
@Override
protected Object parse(String json) {
try {
return objectMapper.readValue(json, new TypeReference<List<String>>() {});
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

@ -0,0 +1,32 @@
package com.supervision.police.controller;
import com.supervision.common.domain.R;
import com.supervision.police.service.LongTextService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Authorlongbao
* @Date2024/12/10 10:20
* @Description: QA
*/
@Slf4j
@RestController
@RequestMapping("/answerLongText")
public class LongTextController {
@Autowired
private LongTextService longTextService;
@Operation(summary = "笔录长文本三元组提取")
@GetMapping("/tripletExtraction")
public R<Object> answerLongTextTripletExtraction(String noteRecordId) {
return longTextService.qaAnswerLongTextTripletExtractionByNoteRecordId(noteRecordId);
}
}

@ -0,0 +1,18 @@
package com.supervision.police.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-11
*/
@RestController
@RequestMapping("/police/model-piece-record-type")
public class ModelPieceRecordTypeController {
}

@ -0,0 +1,18 @@
package com.supervision.police.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@RestController
@RequestMapping("/police/note-piece-prompt")
public class NotePiecePromptController {
}

@ -0,0 +1,18 @@
package com.supervision.police.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@RestController
@RequestMapping("/police/note-piece-prompt-type-rel")
public class NotePiecePromptTypeRelController {
}

@ -0,0 +1,18 @@
package com.supervision.police.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-11
*/
@RestController
@RequestMapping("/police/note-record-split-piece-sentence")
public class NoteRecordSplitPieceSentenceController {
}

@ -0,0 +1,18 @@
package com.supervision.police.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-10
*/
@RestController
@RequestMapping("/police/note-record-split-sentence")
public class NoteRecordSplitSentenceController {
}

@ -0,0 +1,18 @@
package com.supervision.police.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@RestController
@RequestMapping("/police/piece-triple-info")
public class PieceTripleInfoController {
}

@ -0,0 +1,56 @@
package com.supervision.police.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-11
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("model_piece_record_type")
@ApiModel(value = "ModelPieceRecordType对象", description = "笔录同语义类型表")
public class ModelPieceRecordType implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键")
@TableId(value = "id")
private String id;
@ApiModelProperty("笔录语句段类型(总结)")
@TableField("record_type")
private String recordType;
@ApiModelProperty("创建人ID")
@TableField("create_user_id")
private String createUserId;
@ApiModelProperty("创建时间")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty("更新人")
@TableField("update_user_id")
private String updateUserId;
@ApiModelProperty("更新时间")
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

@ -0,0 +1,85 @@
package com.supervision.police.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("note_piece_prompt")
@ApiModel(value = "NotePiecePrompt对象", description = "长文本提示词表")
public class NotePiecePrompt implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键id")
@TableId(value = "id")
private String id;
@ApiModelProperty("提示词")
@TableField("prompt")
private String prompt;
@ApiModelProperty("开始节点类型")
@TableField("start_entity_type")
private String startEntityType;
@ApiModelProperty("开始节点占位符")
@TableField("start_entity_template")
private String startEntityTemplate;
@ApiModelProperty("关系类型")
@TableField("rel_type")
private String relType;
@ApiModelProperty("名称")
@TableField("name")
private String name;
@ApiModelProperty("关系占位符")
@TableField("rel_template")
private String relTemplate;
@ApiModelProperty("结束节点类型")
@TableField("end_entity_type")
private String endEntityType;
@ApiModelProperty("结束节点占位符")
@TableField("end_entity_template")
private String endEntityTemplate;
@ApiModelProperty("创建人ID")
@TableField("create_user_id")
private String createUserId;
@ApiModelProperty("创建时间")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty("更新人")
@TableField("update_user_id")
private String updateUserId;
@ApiModelProperty("更新时间")
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

@ -0,0 +1,42 @@
package com.supervision.police.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("note_piece_prompt_type_rel")
@ApiModel(value = "NotePiecePromptTypeRel对象", description = "句子三元组提示词和分类关系表")
public class NotePiecePromptTypeRel implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键id")
@TableId(value = "id")
private String id;
@ApiModelProperty("note_piece_prompt表ID")
@TableField("prompt_id")
private String promptId;
@ApiModelProperty("id(model_piece_record_type)")
@TableField("type_id")
private String typeId;
}

@ -0,0 +1,77 @@
package com.supervision.police.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import com.supervision.handler.StringListTypeHandler;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-11
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("note_record_split_piece_sentence")
@ApiModel(value = "NoteRecordSplitPieceSentence对象", description = "笔录相同语义片段表")
public class NoteRecordSplitPieceSentence implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键id")
@TableId(value = "id")
private String id;
@ApiModelProperty("笔录片段表id")
@TableField("record_split_id")
private String recordSplitId;
// @ApiModelProperty("同语义片段")
// @TableField(value = "content_chuck", typeHandler = StringListTypeHandler.class)
// private List<String> contentChuck;
@ApiModelProperty("同语义片段")
@TableField(value = "content_chuck")
private String contentChuck;
@ApiModelProperty("片段内容总结")
@TableField("content_chuck_summary")
private String contentChuckSummary;
@ApiModelProperty("备用字段")
@TableField("extend")
private String extend;
@ApiModelProperty("创建人ID")
@TableField("create_user_id")
private String createUserId;
@ApiModelProperty("创建时间")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty("更新人")
@TableField("update_user_id")
private String updateUserId;
@ApiModelProperty("更新时间")
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

@ -0,0 +1,73 @@
package com.supervision.police.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-10
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("note_record_split_sentence")
@ApiModel(value = "NoteRecordSplitSentence对象", description = "长文本单句表")
public class NoteRecordSplitSentence implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("笔录片段表id")
@TableField("record_split_id")
private String recordSplitId;
@ApiModelProperty("笔录相同语义片段表id")
@TableField("piece_record_split_id")
private String pieceRecordSplitId;
@ApiModelProperty("回答")
@TableField("answer")
private String answer;
@ApiModelProperty("句子模型总结内容")
@TableField("llm_gen_a")
private String llmGenA;
@ApiModelProperty("备用字段")
@TableField("extend_one")
private String extendOne;
@ApiModelProperty("创建人ID")
@TableField("create_user_id")
private String createUserId;
@ApiModelProperty("创建时间")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty("更新人")
@TableField("update_user_id")
private String updateUserId;
@ApiModelProperty("更新时间")
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

@ -0,0 +1,102 @@
package com.supervision.police.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("piece_triple_info")
@ApiModel(value = "PieceTripleInfo对象", description = "长文本三元组信息表")
public class PieceTripleInfo implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键id")
@TableId(value = "id")
private String id;
@ApiModelProperty("开始节点")
@TableField("start_node")
private String startNode;
@ApiModelProperty("结束节点")
@TableField("end_node")
private String endNode;
@ApiModelProperty("关系")
@TableField("relation")
private String relation;
@ApiModelProperty("笔录片段id")
@TableField("record_split_id")
private String recordSplitId;
@ApiModelProperty("同语义片段id")
@TableField("piece_record_split_id")
private String pieceRecordSplitId;
@ApiModelProperty("实际提交给大模型的提示词")
@TableField("submit_prompt")
private String submitPrompt;
@ApiModelProperty("是否生成图谱")
@TableField("add_neo4j")
private String addNeo4j;
@ApiModelProperty("创建时间")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty("起始节点图ID")
@TableField("start_node_graph_id")
private Long startNodeGraphId;
@ApiModelProperty("关系ID(neo4j关系id)")
@TableField("rel_graph_id")
private Long relGraphId;
@ApiModelProperty("结束节点图ID")
@TableField("end_node_graph_id")
private Long endNodeGraphId;
@ApiModelProperty("开始节点类型(neo4j节点类型)")
@TableField("start_node_type")
private String startNodeType;
@ApiModelProperty("结束节点类型(neo4j节点类型)")
@TableField("end_node_type")
private String endNodeType;
@ApiModelProperty("创建人ID")
@TableField("create_user_id")
private String createUserId;
@ApiModelProperty("更新人")
@TableField("update_user_id")
private String updateUserId;
@ApiModelProperty("更新时间")
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

@ -0,0 +1,20 @@
package com.supervision.police.dto;
import lombok.Data;
import java.util.List;
/**
* @Authorlongbao
* @Date2024/12/10 14:19
* @Description:
*/
@Data
public class LongTextPieceSentenceDto {
// 笔录片段 长文本单句 id
private List<String> noteRecordSplitSentenceId;
// 笔录片段 长文本同语义id
private String noteRecordSplitPieceSentenceId;
}

@ -0,0 +1,21 @@
package com.supervision.police.dto;
import com.supervision.police.domain.NoteRecordSplitSentence;
import lombok.Data;
import java.util.List;
/**
* @Authorlongbao
* @Date2024/12/10 14:19
* @Description:
*/
@Data
public class LongTextSingleSentenceSummaryDto {
// 笔录片段id
private String noteRecordSplitId;
// 笔录片段单句集合
private List<NoteRecordSplitSentence> noteRecordSplitSentences;
}

@ -0,0 +1,29 @@
package com.supervision.police.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* @Authorlongbao
* @Date2024/12/10 14:19
* @Description: 使 id
*/
@Data
public class PieceSentenceIdDto {
// 同语义句id
private String noteRecordSplitPieceSentenceId;
// 单语句 id集合
private List<Long> noteRecordSplitSentenceId;
public PieceSentenceIdDto() {
}
public PieceSentenceIdDto(String noteRecordSplitPieceSentenceId, List<Long> noteRecordSplitSentenceId) {
this.noteRecordSplitPieceSentenceId = noteRecordSplitPieceSentenceId;
this.noteRecordSplitSentenceId = noteRecordSplitSentenceId;
}
}

@ -0,0 +1,18 @@
package com.supervision.police.mapper;
import com.supervision.police.domain.ModelPieceRecordType;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper
* </p>
*
* @author longbao
* @since 2024-12-11
*/
@Mapper
public interface ModelPieceRecordTypeMapper extends BaseMapper<ModelPieceRecordType> {
}

@ -0,0 +1,18 @@
package com.supervision.police.mapper;
import com.supervision.police.domain.NotePiecePrompt;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Mapper
public interface NotePiecePromptMapper extends BaseMapper<NotePiecePrompt> {
}

@ -0,0 +1,18 @@
package com.supervision.police.mapper;
import com.supervision.police.domain.NotePiecePromptTypeRel;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Mapper
public interface NotePiecePromptTypeRelMapper extends BaseMapper<NotePiecePromptTypeRel> {
}

@ -0,0 +1,18 @@
package com.supervision.police.mapper;
import com.supervision.police.domain.NoteRecordSplitPieceSentence;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper
* </p>
*
* @author longbao
* @since 2024-12-11
*/
@Mapper
public interface NoteRecordSplitPieceSentenceMapper extends BaseMapper<NoteRecordSplitPieceSentence> {
}

@ -0,0 +1,26 @@
package com.supervision.police.mapper;
import com.supervision.police.domain.NoteRecordSplitSentence;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* Mapper
* </p>
*
* @author longbao
* @since 2024-12-10
*/
@Mapper
public interface NoteRecordSplitSentenceMapper extends BaseMapper<NoteRecordSplitSentence> {
void saveBatchList(List<NoteRecordSplitSentence> noteRecordSplitList);
void updateBatchList(@Param("ids") List<Long> ids, @Param("noteRecordSplitPieceSentences") Long noteRecordSplitPieceSentences);
}

@ -0,0 +1,18 @@
package com.supervision.police.mapper;
import com.supervision.police.domain.PieceTripleInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Mapper
public interface PieceTripleInfoMapper extends BaseMapper<PieceTripleInfo> {
}

@ -0,0 +1,22 @@
package com.supervision.police.service;
import com.supervision.common.domain.R;
import java.sql.SQLException;
/**
* @Authorlongbao
* @Date2024/12/10 10:21
* @Description: id
*/
public interface LongTextService {
/**
* id
*
* @param noteRecordId id
* @return
*/
public R<Object> qaAnswerLongTextTripletExtractionByNoteRecordId(String noteRecordId);
}

@ -0,0 +1,16 @@
package com.supervision.police.service;
import com.supervision.police.domain.ModelPieceRecordType;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-11
*/
public interface ModelPieceRecordTypeService extends IService<ModelPieceRecordType> {
}

@ -0,0 +1,29 @@
package com.supervision.police.service;
import com.supervision.police.domain.NotePiecePrompt;
import com.baomidou.mybatisplus.extension.service.IService;
import com.supervision.police.domain.NotePrompt;
import com.supervision.police.domain.NoteRecordSplitPieceSentence;
import java.util.List;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
public interface NotePiecePromptService extends IService<NotePiecePrompt> {
/**
*
* @param recordSplitId
* @return
*/
List<NotePiecePrompt> listPiecePromptBySplitId(NoteRecordSplitPieceSentence recordSplitId);
}

@ -0,0 +1,16 @@
package com.supervision.police.service;
import com.supervision.police.domain.NotePiecePromptTypeRel;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
public interface NotePiecePromptTypeRelService extends IService<NotePiecePromptTypeRel> {
}

@ -0,0 +1,16 @@
package com.supervision.police.service;
import com.supervision.police.domain.NoteRecordSplitPieceSentence;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-11
*/
public interface NoteRecordSplitPieceSentenceService extends IService<NoteRecordSplitPieceSentence> {
}

@ -0,0 +1,32 @@
package com.supervision.police.service;
import com.supervision.police.domain.NoteRecordSplitSentence;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-10
*/
public interface NoteRecordSplitSentenceService extends IService<NoteRecordSplitSentence> {
/**
*
* @param noteRecordSplitList
*/
public void saveBatchList(List<NoteRecordSplitSentence> noteRecordSplitList);
/**
* llmGenA
* @param ids id
* @param noteRecordSplitPieceSentences id
*/
void updateBatchList(List<Long> ids,Long noteRecordSplitPieceSentences);
}

@ -0,0 +1,16 @@
package com.supervision.police.service;
import com.supervision.police.domain.PieceTripleInfo;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
public interface PieceTripleInfoService extends IService<PieceTripleInfo> {
}

@ -0,0 +1,750 @@
package com.supervision.police.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.supervision.common.domain.R;
import com.supervision.common.utils.StringUtils;
import com.supervision.constant.PromptsEnum;
import com.supervision.police.domain.*;
import com.supervision.police.dto.LongTextSingleSentenceSummaryDto;
import com.supervision.police.dto.PieceSentenceIdDto;
import com.supervision.police.service.*;
import com.supervision.thread.*;
import com.supervision.utils.UserUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.ollama.OllamaChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Authorlongbao
* @Date2024/12/10 10:22
* @Description: QA
*/
@Slf4j
@Service
public class LongTextServiceImpl implements LongTextService {
private static final String HEAD_ENTITY_TYPE_ACTOR = "行为人";
@Autowired
private NoteRecordService noteRecordService;
@Autowired
private NoteRecordSplitService noteRecordSplitService;
@Autowired
private NoteRecordSplitSentenceService noteRecordSplitSentenceService;
@Autowired
private OllamaChatClient chatClient;
@Autowired
private NoteRecordSplitPieceSentenceService noteRecordSplitPieceSentenceService;
@Autowired
private ModelPieceRecordTypeService modelPieceRecordTypeService;
@Autowired
private NotePiecePromptTypeRelService notePiecePromptTypeRelService;
@Autowired
private NotePiecePromptService notePiecePromptService;
@Autowired
private CasePersonService casePersonService;
@Autowired
private PieceTripleInfoService pieceTripleInfoService;
/**
* id
*
* @param noteRecordId id
* @return
*/
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
public R<Object> qaAnswerLongTextTripletExtractionByNoteRecordId(String noteRecordId) {
log.info("[QaAnswerLongTextTripletExtraction]开始");
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 校验参数
if (StringUtils.isNull(noteRecordId)) {
stopWatch.stop();
log.error("[QaAnswerLongTextTripletExtraction]笔录id不存在{}", noteRecordId);
log.warn("[QaAnswerLongTextTripletExtraction]主线程程序总耗时:{}", stopWatch.getTotalTimeSeconds());
return R.fail("笔录id不可为空");
}
// 查询笔录是否存在
NoteRecord noteRecord = noteRecordService
.lambdaQuery()
.select(NoteRecord::getId)
.eq(NoteRecord::getId, noteRecordId)
.one();
if (null == noteRecord) {
stopWatch.stop();
log.error("[QaAnswerLongTextTripletExtraction]笔录不存在{}", noteRecordId);
log.warn("[QaAnswerLongTextTripletExtraction]主线程程序总耗时:{}", stopWatch.getTotalTimeSeconds());
return R.fail("该笔录不存在");
}
// 笔录是否已拆分QA
List<NoteRecordSplit> noteRecordSplits = noteRecordSplitService
.lambdaQuery()
.select(NoteRecordSplit::getId, NoteRecordSplit::getAnswer)
.eq(NoteRecordSplit::getNoteRecordId, noteRecordId)
.list();
if (null == noteRecordSplits || noteRecordSplits.isEmpty()) {
stopWatch.stop();
log.error("[QaAnswerLongTextTripletExtraction]笔录未拆分{}", noteRecordId);
log.warn("[QaAnswerLongTextTripletExtraction]主线程程序总耗时:{}", stopWatch.getTotalTimeSeconds());
return R.fail("该笔录未拆分QA对");
}
R<Object> threadPoolExecutorCheck = singlePointCheck();
if (null != threadPoolExecutorCheck) {
stopWatch.stop();
return threadPoolExecutorCheck;
}
// 获取笔录片段中回答中的长文本
List<NoteRecordSplitSentence> noteRecordSplitList = matcherLongText(noteRecordSplits);
if (noteRecordSplitList.isEmpty()) {
stopWatch.stop();
log.error("[QaAnswerLongTextTripletExtraction]笔录无长文本{}", noteRecordId);
log.warn("[QaAnswerLongTextTripletExtraction]主线程程序总耗时:{}", stopWatch.getTotalTimeSeconds());
return R.fail("该笔录QA对未查询到长文本");
}
log.info("[QaAnswerLongTextTripletExtraction]校验通过");
// 保存长文本单句
noteRecordSplitSentenceService.saveBatch(noteRecordSplitList);
log.info("[QaAnswerLongTextTripletExtraction]保存长文本单句成功");
// 长文本单句总结
List<String> noteRecordSplitAnswerList = new ArrayList<>();
for (NoteRecordSplitSentence noteRecordSplitSentence : noteRecordSplitList) {
Long noteRecordSplitSentenceId = noteRecordSplitSentence.getId();
String answer = noteRecordSplitSentence.getAnswer();
noteRecordSplitAnswerList.add(noteRecordSplitSentenceId + "、" + answer);
}
log.info("[QaAnswerLongTextTripletExtraction]长文本单句总结开始");
List<NoteRecordSplitSentence> noteRecordSplitSentences = chatAiLongTextSingleSentenceSummary(PromptsEnum.LONG_TEXT_SINGLE_SENTENCE_SUMMARY, noteRecordSplitAnswerList);
log.info("[QaAnswerLongTextTripletExtraction]长文本单句总结结束");
// 更新长文本单句
noteRecordSplitSentenceService.updateBatchById(noteRecordSplitSentences);
log.info("[QaAnswerLongTextTripletExtraction]更新长文本单句成功");
// 获取answer片段对应的单句集合
List<Long> noteRecordSplitSentenceIdList = noteRecordSplitList
.stream()
.map(NoteRecordSplitSentence::getId)
.toList();
List<LongTextSingleSentenceSummaryDto> longTextSingleSentenceSummaryDtoList = new ArrayList<>();
List<NoteRecordSplitSentence> splitSentences = noteRecordSplitSentenceService
.lambdaQuery()
.select(NoteRecordSplitSentence::getRecordSplitId)
.in(NoteRecordSplitSentence::getId, noteRecordSplitSentenceIdList)
.groupBy(NoteRecordSplitSentence::getRecordSplitId)
.list();
// 遍历长文本单句
for (NoteRecordSplitSentence noteRecordSplit : splitSentences) {
String noteRecordSplitId = noteRecordSplit.getRecordSplitId();
List<NoteRecordSplitSentence> recordSplitSentenceList = noteRecordSplitSentenceService
.lambdaQuery()
.eq(NoteRecordSplitSentence::getRecordSplitId, noteRecordSplitId)
.in(NoteRecordSplitSentence::getId, noteRecordSplitSentenceIdList)
.orderByAsc(NoteRecordSplitSentence::getId)
.list();
LongTextSingleSentenceSummaryDto longTextSingleSentenceSummaryDto = new LongTextSingleSentenceSummaryDto();
longTextSingleSentenceSummaryDto.setNoteRecordSplitId(noteRecordSplitId);
longTextSingleSentenceSummaryDto.setNoteRecordSplitSentences(recordSplitSentenceList);
longTextSingleSentenceSummaryDtoList.add(longTextSingleSentenceSummaryDto);
}
if (longTextSingleSentenceSummaryDtoList.isEmpty()) {
log.warn("[QaAnswerLongTextTripletExtraction]当前回答下的单句集合不可为空");
return R.fail("当前回答下的长文本单句集合为空");
}
log.info("[QaAnswerLongTextTripletExtraction]当前回答下的单句集合查询成功");
try {
// 遍历单句集合-同语义归纳
List<Future<Map<String, Object>>> futureList = new ArrayList<>();
for (LongTextSingleSentenceSummaryDto longTextSingleSentenceSummaryDto : longTextSingleSentenceSummaryDtoList) {
LongTextTask longTextTask = new LongTextTask(chatClient, longTextSingleSentenceSummaryDto, pieceSentenceSave());
Future<Map<String, Object>> submit = LongtextThreadPool.executorService.submit(longTextTask);
futureList.add(submit);
}
log.info("[QaAnswerLongTextTripletExtraction]:同语义归纳任务成功提交{}个任务....", futureList.size());
} catch (Exception e) {
log.error("[QaAnswerLongTextTripletExtraction]未知异常:", e);
return R.fail("长文本接口未知异常");
} finally {
stopWatch.stop();
log.warn("[QaAnswerLongTextTripletExtraction]主线程程序总耗时:{}", stopWatch.getTotalTimeSeconds());
}
return null;
}
/**
*
*
* @param noteRecordSplitPieceSentence
* @return person- notePromptList-
*/
private Map<String, Object> queryPromptByType(NoteRecordSplitPieceSentence noteRecordSplitPieceSentence) {
log.info("longTextExtractTripleInfo:同语义句类型查询开始");
Map<String, Object> returnMap = new HashMap<>();
// 判断同语义类型是否存在
String pieceSentenceId = noteRecordSplitPieceSentence.getId();
String contentChuck = noteRecordSplitPieceSentence.getContentChuckSummary();
if (null == contentChuck || contentChuck.isEmpty()) {
log.warn("longTextExtractTripleInfo:同语义片段片段:{} 不存在任何分类信息,不进行后续操作...", pieceSentenceId);
return null;
}
// 查询 同语义类型 对应的 提示词集合
List<NotePiecePrompt> notePromptList = notePiecePromptService.listPiecePromptBySplitId(noteRecordSplitPieceSentence);
if (CollUtil.isEmpty(notePromptList)) {
log.warn("longTextExtractTripleInfo:同语义片段:{},分类:{} 不属于任何提示词,不进行后续操作...", pieceSentenceId, contentChuck);
return null;
}
// 查询笔录的案件信息
String recordSplitId = noteRecordSplitPieceSentence.getRecordSplitId();
NoteRecordSplit recordSplit = noteRecordSplitService.lambdaQuery().select(NoteRecordSplit::getCaseId).eq(NoteRecordSplit::getId, recordSplitId).one();
QueryWrapper<CasePerson> wrapper = new QueryWrapper<>();
wrapper.eq("case_id", recordSplit.getCaseId());
wrapper.eq("case_actor_flag", 1);
CasePerson personServiceOne = casePersonService.getOne(wrapper);
returnMap.put("person", personServiceOne);
returnMap.put("notePromptList", notePromptList);
return returnMap;
}
/**
*
*
* @return
*/
private Consumer<Map<String, Object>> pieceSentenceSave() throws Exception {
return (noteMap) -> {
log.info("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]同语义保存,当前线程是:{}", Thread.currentThread().getName());
String contentChuck;
List<NoteRecordSplitPieceSentence> recordSplitPieceSentences = (List<NoteRecordSplitPieceSentence>) noteMap.get("recordSplitPieceSentences");
List<PieceSentenceIdDto> noteRecordSplitPieceSentenceBySingle = (List<PieceSentenceIdDto>) noteMap.get("noteRecordSplitPieceSentenceBySingle");
// 保存同语义集合
noteRecordSplitPieceSentenceService.saveBatch(recordSplitPieceSentences);
// 更新单语句 的 长语句id
for (PieceSentenceIdDto pieceSentenceIdDto : noteRecordSplitPieceSentenceBySingle) {
List<NoteRecordSplitSentence> recordSplitSentences = getNoteRecordSplitSentences(pieceSentenceIdDto);
noteRecordSplitSentenceService.updateBatchById(recordSplitSentences);
}
// 保存 提示词
NotePiecePrompt piecePrompt = notePiecePromptService.lambdaQuery().eq(NotePiecePrompt::getName, "行为人-担保-xxxx").one();
if (null == piecePrompt) {
NotePiecePrompt notePiecePrompt = getNotePiecePrompt();
notePiecePromptService.save(notePiecePrompt);
piecePrompt = notePiecePrompt;
}
// 更新同语义总结
List<NoteRecordSplitPieceSentence> noteRecordSplitPieceSentences = new ArrayList<>();
List<ModelPieceRecordType> modelPieceRecordTypes = new ArrayList<>();
List<NotePiecePromptTypeRel> notePiecePromptTypeRels = new ArrayList<>();
for (NoteRecordSplitPieceSentence noteRecordSplitPieceSentence : recordSplitPieceSentences) {
String splitPieceSentenceId = noteRecordSplitPieceSentence.getId();
List<NoteRecordSplitSentence> splitSentence = noteRecordSplitSentenceService.lambdaQuery()
.select(NoteRecordSplitSentence::getLlmGenA)
.isNotNull(NoteRecordSplitSentence::getLlmGenA)
.ne(NoteRecordSplitSentence::getLlmGenA, "无")
.eq(NoteRecordSplitSentence::getPieceRecordSplitId, splitPieceSentenceId)
.list();
if (null != splitSentence && !splitSentence.isEmpty()) {
// 更新同语义总结
contentChuck = splitSentence.get(0).getLlmGenA();
} else {
// 重新请求模型生成同语义句子的语义
List<String> noteRecordSplitAnswerList = new ArrayList<>();
noteRecordSplitAnswerList.add(noteRecordSplitPieceSentence.getContentChuck());
contentChuck = ((chatAiLongTextSingleSentenceSummary(PromptsEnum.LONG_TEXT_SINGLE_SENTENCE_SUMMARY, noteRecordSplitAnswerList).get(0)) == null) ? "无"
: (chatAiLongTextSingleSentenceSummary(PromptsEnum.LONG_TEXT_SINGLE_SENTENCE_SUMMARY, noteRecordSplitAnswerList).get(0).getLlmGenA());
}
NoteRecordSplitPieceSentence splitPieceSentence = new NoteRecordSplitPieceSentence();
splitPieceSentence.setId(splitPieceSentenceId);
splitPieceSentence.setContentChuckSummary(contentChuck);
noteRecordSplitPieceSentences.add(splitPieceSentence);
// 类型
String modelPieceRecordTypeId = DefaultIdentifierGenerator.getInstance().nextId(null).toString();
ModelPieceRecordType modelPieceRecordType = new ModelPieceRecordType();
modelPieceRecordType.setId(modelPieceRecordTypeId);
modelPieceRecordType.setRecordType(contentChuck);
modelPieceRecordType.setCreateUserId(UserUtil.getUser().getId());
modelPieceRecordType.setUpdateUserId(UserUtil.getUser().getId());
modelPieceRecordTypes.add(modelPieceRecordType);
// 保存 类型 提示词关系
String notePiecePromptTypeRelId = DefaultIdentifierGenerator.getInstance().nextId(null).toString();
NotePiecePromptTypeRel notePiecePromptTypeRel = new NotePiecePromptTypeRel();
notePiecePromptTypeRel.setId(notePiecePromptTypeRelId);
notePiecePromptTypeRel.setPromptId(piecePrompt.getId());
notePiecePromptTypeRel.setTypeId(modelPieceRecordType.getId());
notePiecePromptTypeRels.add(notePiecePromptTypeRel);
}
// 更新同语义句的总结(类型)
noteRecordSplitPieceSentenceService.updateBatchById(noteRecordSplitPieceSentences);
// 保存同语义总结(类型)
modelPieceRecordTypeService.saveBatch(modelPieceRecordTypes);
// 保存 类型 提示词关系
notePiecePromptTypeRelService.saveBatch(notePiecePromptTypeRels);
log.info("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]保存类型+总结+提示词成功,当前线程是:{}", Thread.currentThread().getName());
// 12.三元组提取
// 查询同语义句
log.info("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]开始同语义三元组提取。当前线程是:{}", Thread.currentThread().getName());
List<String> notePieceSentencesIdList = recordSplitPieceSentences.stream().map(NoteRecordSplitPieceSentence::getId).toList();
List<NoteRecordSplitPieceSentence> notePieceSentences = noteRecordSplitPieceSentenceService
.lambdaQuery()
.select(NoteRecordSplitPieceSentence::getId, NoteRecordSplitPieceSentence::getRecordSplitId, NoteRecordSplitPieceSentence::getContentChuck, NoteRecordSplitPieceSentence::getContentChuckSummary)
.in(NoteRecordSplitPieceSentence::getId, notePieceSentencesIdList)
.list();
// 遍历同语义句
for (NoteRecordSplitPieceSentence noteRecordSplitPieceSentence : notePieceSentences) {
Map<String, Object> queryPromptByType = queryPromptByType(noteRecordSplitPieceSentence);
if (null == queryPromptByType) {
log.warn("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]同语义查询案件信息或提示词为null,noteRecordSplitPieceSentenceId:{},当前线程是:{}", noteRecordSplitPieceSentence.getId(), Thread.currentThread().getName());
continue;
}
CasePerson mainActor = (CasePerson) queryPromptByType.get("person");
List<NotePiecePrompt> notePromptList = (List<NotePiecePrompt>) queryPromptByType.get("notePromptList");
if (null == mainActor || CollUtil.isEmpty(notePromptList)) {
log.warn("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]该同语义句三元组提示词或案件信息缺失,noteRecordSplitPieceSentenceId:{},当前线程是:{}", noteRecordSplitPieceSentence.getId(), Thread.currentThread().getName());
continue;
}
List<Future<PieceTripleInfo>> futures = new ArrayList<>();
for (NotePiecePrompt notePiecePrompt : notePromptList) {
PieceTripleExtractTask pieceTripleExtractTask = new PieceTripleExtractTask(chatClient, mainActor, notePiecePrompt, noteRecordSplitPieceSentence);
Future<PieceTripleInfo> submit = PieceTripleThreadPool.executorService.submit(pieceTripleExtractTask);
futures.add(submit);
}
List<PieceTripleInfo> tripleInfos = new ArrayList<>();
try {
log.info("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]当前线程{},同语义片段:{}三元组抽取任务成功提交{}个任务....", Thread.currentThread().getName(), noteRecordSplitPieceSentence.getId(), futures.size());
for (Future<PieceTripleInfo> future : futures) {
PieceTripleInfo tripleInfo = future.get();
if (Objects.nonNull(tripleInfo)) {
tripleInfos.add(tripleInfo);
}
}
// 如果有提取到三元组信息
if (CollUtil.isNotEmpty(tripleInfos)) {
log.info("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]当前线程{},同语义片段:{}三元组提取任务执行结束...,三元组信息入库:{}", Thread.currentThread().getName(), noteRecordSplitPieceSentence.getId(), JSONUtil.toJsonStr(tripleInfos));
pieceTripleInfoService.saveBatch(tripleInfos);
} else {
log.info("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]当前线程{},同语义片段:{}三元组提取任务执行结束...,未提取到任何三元组信息...", Thread.currentThread().getName(), noteRecordSplitPieceSentence.getId());
}
} catch (InterruptedException | ExecutionException e) {
log.error("[QaAnswerLongTextTripletExtraction-Pool-pieceSentenceSave]当前线程{},同语义片段:{}三元组提取任务提交失败...", Thread.currentThread().getName(), noteRecordSplitPieceSentence.getId(), e);
throw new RuntimeException(e);
}
}
};
}
/**
*
*
* @param longTextSingleSentenceSummaryDto
*/
private void pieceSentenceNormal(LongTextSingleSentenceSummaryDto longTextSingleSentenceSummaryDto) {
log.info("[pieceSentenceNormal]开始同语义归纳方法");
String contentChuck = "";
// 同语义集合
List<NoteRecordSplitPieceSentence> recordSplitPieceSentences = new ArrayList<>();
// 同语义使用单句id集合
List<PieceSentenceIdDto> noteRecordSplitPieceSentenceBySingle = new ArrayList<>();
// 笔录片段id
String noteRecordSplitId = longTextSingleSentenceSummaryDto.getNoteRecordSplitId();
// 单语句集合
List<NoteRecordSplitSentence> noteRecordSplitSentences = longTextSingleSentenceSummaryDto.getNoteRecordSplitSentences();
int noteRecordSplitSentencesSize = noteRecordSplitSentences.size();
// 获取末尾单句 N+1
NoteRecordSplitSentence endCombinedSentence = noteRecordSplitSentences.get(noteRecordSplitSentencesSize - 1);
Long endCombinedSentenceId = endCombinedSentence.getId();
ConcurrentLinkedDeque<Long> noteRecordSplitPieceSentenceDeque = new ConcurrentLinkedDeque<>();
noteRecordSplitPieceSentenceDeque.add(endCombinedSentenceId);
ConcurrentLinkedDeque<String> endCombinedSentenceDeque = new ConcurrentLinkedDeque<>();
endCombinedSentenceDeque.addLast(endCombinedSentence.getAnswer());
// 遍历单句集合
for (int i = noteRecordSplitSentencesSize - 2; i >= 0; i--) {
PieceSentenceIdDto pieceSentenceIdDto = new PieceSentenceIdDto();
// 获取第N句
NoteRecordSplitSentence currentSentence = noteRecordSplitSentences.get(i);
Long currentSentenceId = currentSentence.getId();
String currentSentenceAnswer = currentSentence.getAnswer();
// 对比句子语义
boolean inductionFlag = chatAiLongTextHomoSemanticInduction(String.valueOf(endCombinedSentenceDeque), currentSentenceAnswer);
if (inductionFlag) {
endCombinedSentenceDeque.addFirst(currentSentenceAnswer);
noteRecordSplitPieceSentenceDeque.addFirst(currentSentenceId);
} else {
NoteRecordSplitPieceSentence pieceSentence = setNotePieceRecordSentence(noteRecordSplitId, endCombinedSentenceDeque);
endCombinedSentenceDeque.remove();
endCombinedSentenceDeque.addLast(currentSentenceAnswer);
List<Long> longList = noteRecordSplitPieceSentenceDeque.stream().toList();
noteRecordSplitPieceSentenceDeque.remove();
noteRecordSplitPieceSentenceDeque.addLast(currentSentenceId);
pieceSentenceIdDto.setNoteRecordSplitPieceSentenceId(pieceSentence.getId());
pieceSentenceIdDto.setNoteRecordSplitSentenceId(longList);
recordSplitPieceSentences.add(pieceSentence);
noteRecordSplitPieceSentenceBySingle.add(pieceSentenceIdDto);
}
}
NoteRecordSplitPieceSentence pieceSentence = setNotePieceRecordSentence(noteRecordSplitId, endCombinedSentenceDeque);
recordSplitPieceSentences.add(pieceSentence);
noteRecordSplitPieceSentenceBySingle.add(new PieceSentenceIdDto(pieceSentence.getId(), noteRecordSplitPieceSentenceDeque.stream().toList()));
// 保存同语义集合
noteRecordSplitPieceSentenceService.saveBatch(recordSplitPieceSentences);
// 更新单语句 的 长语句id
for (PieceSentenceIdDto pieceSentenceIdDto : noteRecordSplitPieceSentenceBySingle) {
List<NoteRecordSplitSentence> recordSplitSentences = getNoteRecordSplitSentences(pieceSentenceIdDto);
noteRecordSplitSentenceService.updateBatchById(recordSplitSentences);
}
// 保存 提示词
NotePiecePrompt piecePrompt = notePiecePromptService.lambdaQuery().eq(NotePiecePrompt::getName, "行为人-担保-xxxx").one();
if (null == piecePrompt) {
NotePiecePrompt notePiecePrompt = getNotePiecePrompt();
notePiecePromptService.save(notePiecePrompt);
piecePrompt = notePiecePrompt;
}
// 更新同语义总结
List<NoteRecordSplitPieceSentence> noteRecordSplitPieceSentences = new ArrayList<>();
List<ModelPieceRecordType> modelPieceRecordTypes = new ArrayList<>();
List<NotePiecePromptTypeRel> notePiecePromptTypeRels = new ArrayList<>();
for (NoteRecordSplitPieceSentence noteRecordSplitPieceSentence : recordSplitPieceSentences) {
String splitPieceSentenceId = noteRecordSplitPieceSentence.getId();
List<NoteRecordSplitSentence> splitSentence = noteRecordSplitSentenceService.lambdaQuery()
.select(NoteRecordSplitSentence::getLlmGenA)
.isNotNull(NoteRecordSplitSentence::getLlmGenA)
.ne(NoteRecordSplitSentence::getLlmGenA, "无")
.eq(NoteRecordSplitSentence::getPieceRecordSplitId, splitPieceSentenceId)
.list();
if (null != splitSentence && !splitSentence.isEmpty()) {
// 更新同语义总结
contentChuck = splitSentence.get(0).getLlmGenA();
} else {
// 重新请求模型生成同语义句子的语义
List<String> noteRecordSplitAnswerList = new ArrayList<>();
noteRecordSplitAnswerList.add(noteRecordSplitPieceSentence.getContentChuck());
contentChuck = ((chatAiLongTextSingleSentenceSummary(PromptsEnum.LONG_TEXT_SINGLE_SENTENCE_SUMMARY, noteRecordSplitAnswerList).get(0)) == null) ? "无"
: (chatAiLongTextSingleSentenceSummary(PromptsEnum.LONG_TEXT_SINGLE_SENTENCE_SUMMARY, noteRecordSplitAnswerList).get(0).getLlmGenA());
}
NoteRecordSplitPieceSentence splitPieceSentence = new NoteRecordSplitPieceSentence();
splitPieceSentence.setId(splitPieceSentenceId);
splitPieceSentence.setContentChuckSummary(contentChuck);
noteRecordSplitPieceSentences.add(splitPieceSentence);
// 类型
String modelPieceRecordTypeId = DefaultIdentifierGenerator.getInstance().nextId(null).toString();
ModelPieceRecordType modelPieceRecordType = new ModelPieceRecordType();
modelPieceRecordType.setId(modelPieceRecordTypeId);
modelPieceRecordType.setRecordType(contentChuck);
modelPieceRecordType.setCreateUserId(UserUtil.getUser().getId());
modelPieceRecordType.setUpdateUserId(UserUtil.getUser().getId());
modelPieceRecordTypes.add(modelPieceRecordType);
// 保存 类型 提示词关系
String notePiecePromptTypeRelId = DefaultIdentifierGenerator.getInstance().nextId(null).toString();
NotePiecePromptTypeRel notePiecePromptTypeRel = new NotePiecePromptTypeRel();
notePiecePromptTypeRel.setId(notePiecePromptTypeRelId);
notePiecePromptTypeRel.setPromptId(piecePrompt.getId());
notePiecePromptTypeRel.setTypeId(modelPieceRecordType.getId());
notePiecePromptTypeRels.add(notePiecePromptTypeRel);
}
// 更新同语义句的总结(类型)
noteRecordSplitPieceSentenceService.updateBatchById(noteRecordSplitPieceSentences);
// 保存同语义总结(类型)
modelPieceRecordTypeService.saveBatch(modelPieceRecordTypes);
// 保存 类型 提示词关系
notePiecePromptTypeRelService.saveBatch(notePiecePromptTypeRels);
log.info("[pieceSentenceNormal]关系已保存");
}
/**
*
*
* @return
*/
private NotePiecePrompt getNotePiecePrompt() {
NotePiecePrompt notePiecePrompt = new NotePiecePrompt();
notePiecePrompt.setStartEntityType("行为人");
notePiecePrompt.setRelType("担保");
notePiecePrompt.setEndEntityType("xxxx");
notePiecePrompt.setPrompt(PromptsEnum.LONG_TEXT_TRIPLE_INFO.getContent());
notePiecePrompt.setStartEntityTemplate("headEntityType");
notePiecePrompt.setRelTemplate("relation");
notePiecePrompt.setEndEntityTemplate("tailEntityType");
notePiecePrompt.setName("行为人-担保-xxxx");
notePiecePrompt.setCreateUserId(UserUtil.getUser().getId());
notePiecePrompt.setUpdateUserId(UserUtil.getUser().getId());
return notePiecePrompt;
}
/**
* @param prompt
* @param noteRecordSplitAnswerList
* @return
*/
public List<NoteRecordSplitSentence> chatAiLongTextSingleSentenceSummary(PromptsEnum prompt, List<String> noteRecordSplitAnswerList) {
List<NoteRecordSplitSentence> noteRecordSplitSentenceArrayList = new ArrayList<>();
StopWatch stopWatch = new StopWatch();
// 分析同语义集合
stopWatch.start();
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("noteRecordSplitList", noteRecordSplitAnswerList);
String format = StrUtil.format(prompt.getContent(), paramMap);
ChatResponse call = chatClient.call(new Prompt(new UserMessage(format)));
stopWatch.stop();
log.warn("[QaAnswerLongTextTripletExtraction-chatAiLongTextSingleSentenceSummary]长文本单句总结集合模型耗时:{}", stopWatch.getTotalTimeSeconds());
String content = call.getResult().getOutput().getContent();
JSONObject jsonObject = JSON.parseObject(content);
Object object = jsonObject.get("result");
JSONArray jsonArray = JSONArray.parseArray(object.toString());
List<Object> list = jsonArray.stream().toList();
try {
for (Object listObject : list) {
NoteRecordSplitSentence noteRecordSplitSentence = JSONUtil.toBean(String.valueOf(listObject), NoteRecordSplitSentence.class);
noteRecordSplitSentenceArrayList.add(noteRecordSplitSentence);
}
} catch (Exception e) {
log.error("[QaAnswerLongTextTripletExtraction-chatAiLongTextSingleSentenceSummary]长文本单句总结集合模型转换错误");
throw new RuntimeException(e);
}
return noteRecordSplitSentenceArrayList;
}
/**
*
*
* @param noteRecordSplits
* @return
*/
private List<NoteRecordSplitSentence> matcherLongText(List<NoteRecordSplit> noteRecordSplits) {
// 定义正则表达式,匹配“:”,“:”
String regexSplit = "[:]";
// 长文本段落集合
List<NoteRecordSplitSentence> noteRecordSplitList = new ArrayList<>();
// 回答中匹配的长文本段落
String paragraph = null;
for (NoteRecordSplit noteRecordSplit : noteRecordSplits) {
String noteRecordSplitId = noteRecordSplit.getId();
String answer = noteRecordSplit.getAnswer();
if (StringUtils.isEmpty(answer)) {
continue;
}
// 使用 Pattern 和 Matcher 类进行匹配
Pattern pattern = Pattern.compile(regexSplit);
Matcher matcher = pattern.matcher(answer);
boolean isMatch = matcher.find();
if (isMatch) {
String[] answerSplit = answer.split(regexSplit);
paragraph = answerSplit[1];
if (StringUtils.isEmpty(paragraph)) {
continue;
}
}
List<String> splitSentences = splitSentences(paragraph);
int paragraphChar = paragraph.replace("\n", "")
.replace("\t", "")
.replace("\s", "")
.trim().length();
if (splitSentences.size() > 5 || paragraphChar > 100) {
// 长文本
for (String sentence : splitSentences) {
NoteRecordSplitSentence noteRecordSplitSentence = new NoteRecordSplitSentence();
noteRecordSplitSentence.setRecordSplitId(noteRecordSplitId);
noteRecordSplitSentence.setAnswer(sentence);
noteRecordSplitSentence.setCreateUserId(UserUtil.getUser().getId());
noteRecordSplitSentence.setUpdateUserId(UserUtil.getUser().getId());
noteRecordSplitList.add(noteRecordSplitSentence);
}
}
}
return noteRecordSplitList;
}
/**
*
*
* @param paragraph
* @return
*/
private List<String> splitSentences(String paragraph) {
List<String> sentences = new ArrayList<>();
StringBuilder currentSentence = new StringBuilder();
for (char c : paragraph.toCharArray()) {
if (c == '。' || c == '' || c == '' || c == '.' || c == '?' || c == '!') {
sentences.add(currentSentence.append(c).toString().trim());
currentSentence.setLength(0);
} else {
currentSentence.append(c);
}
}
// 处理段落末尾可能没有标点符号的情况
if (!currentSentence.isEmpty()) {
sentences.add(currentSentence.toString().trim());
}
return sentences;
}
/**
* @param encCombinedSentence N+1
* @param currentSentence N
* @return
*/
private boolean chatAiLongTextHomoSemanticInduction(String encCombinedSentence, String currentSentence) {
StopWatch stopWatch = new StopWatch();
// 分析同语义集合
stopWatch.start();
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("encCombinedSentence", encCombinedSentence);
paramMap.put("currentSentence", currentSentence);
String format = StrUtil.format(PromptsEnum.LONG_TEXT_SINGLE_STATEMENT_WITH_SEMANTIC_JUDGMENT_PROMPT_WORD.getContent(), paramMap);
ChatResponse call = chatClient.call(new Prompt(new UserMessage(format)));
stopWatch.stop();
String content = call.getResult().getOutput().getContent();
JSONObject jsonObject = JSON.parseObject(content);
boolean result = (boolean) jsonObject.get("result");
return result;
}
/**
*
*
* @param noteRecordSplitId id
* @param endSentenceDequeStringDeque
* @return
*/
public NoteRecordSplitPieceSentence setNotePieceRecordSentence(String noteRecordSplitId, ConcurrentLinkedDeque<String> endSentenceDequeStringDeque) {
StringBuilder endSentenceDequeStringBuilder = new StringBuilder();
for (String endSentenceDeque : endSentenceDequeStringDeque) {
endSentenceDequeStringBuilder.append(endSentenceDeque);
}
String endSentenceDequeStringBuilderString = String.valueOf(endSentenceDequeStringBuilder);
String noteRecordSplitPieceSentenceId = DefaultIdentifierGenerator.getInstance().nextId(null).toString();
NoteRecordSplitPieceSentence noteRecordSplitPieceSentence = new NoteRecordSplitPieceSentence();
noteRecordSplitPieceSentence.setId(noteRecordSplitPieceSentenceId);
noteRecordSplitPieceSentence.setCreateUserId(UserUtil.getUser().getId());
noteRecordSplitPieceSentence.setUpdateUserId(UserUtil.getUser().getId());
noteRecordSplitPieceSentence.setRecordSplitId(noteRecordSplitId);
noteRecordSplitPieceSentence.setContentChuck(endSentenceDequeStringBuilderString);
return noteRecordSplitPieceSentence;
}
/**
*
*
* @return
*/
public R<Object> singlePointCheck() {
// 检测上个线程池中是否有未完成的任务
ThreadPoolExecutor longTextExecutorService = LongtextThreadPool.executorService;
ThreadPoolExecutor pieceTripleExecutorService = PieceTripleThreadPool.executorService;
int longTextActiveCount = longTextExecutorService.getActiveCount();
boolean longTextEmpty = longTextExecutorService.getQueue().isEmpty();
int pieceTripleActiveCount = pieceTripleExecutorService.getActiveCount();
boolean pieceTripleTextEmpty = longTextExecutorService.getQueue().isEmpty();
if ((longTextActiveCount != 0 || !longTextEmpty) || (pieceTripleActiveCount != 0 || !pieceTripleTextEmpty)) {
log.error("[QaAnswerLongTextTripletExtraction-threadPoolExecutorCheck]线程池中有未完成的任务,请稍后再试");
return R.fail("操作过快,请稍后再试");
}
return null;
}
/**
*
*
* @param pieceSentenceIdDto
* @return
*/
private List<NoteRecordSplitSentence> getNoteRecordSplitSentences(PieceSentenceIdDto pieceSentenceIdDto) {
String noteRecordSplitPieceSentenceId = pieceSentenceIdDto.getNoteRecordSplitPieceSentenceId();
List<Long> noteRecordSplitSentenceId = pieceSentenceIdDto.getNoteRecordSplitSentenceId();
List<NoteRecordSplitSentence> recordSplitSentences = new ArrayList<>();
for (Long recordSplitSentenceId : noteRecordSplitSentenceId) {
NoteRecordSplitSentence noteRecordSplitSentence = new NoteRecordSplitSentence();
noteRecordSplitSentence.setId(recordSplitSentenceId);
noteRecordSplitSentence.setPieceRecordSplitId(noteRecordSplitPieceSentenceId);
recordSplitSentences.add(noteRecordSplitSentence);
}
return recordSplitSentences;
}
}

@ -0,0 +1,20 @@
package com.supervision.police.service.impl;
import com.supervision.police.domain.ModelPieceRecordType;
import com.supervision.police.mapper.ModelPieceRecordTypeMapper;
import com.supervision.police.service.ModelPieceRecordTypeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-11
*/
@Service
public class ModelPieceRecordTypeServiceImpl extends ServiceImpl<ModelPieceRecordTypeMapper, ModelPieceRecordType> implements ModelPieceRecordTypeService {
}

@ -0,0 +1,94 @@
package com.supervision.police.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.supervision.police.domain.*;
import com.supervision.police.mapper.NotePiecePromptMapper;
import com.supervision.police.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class NotePiecePromptServiceImpl extends ServiceImpl<NotePiecePromptMapper, NotePiecePrompt> implements NotePiecePromptService {
private final NotePiecePromptTypeRelService notePiecePromptTypeRelService;
private final ModelPieceRecordTypeService modelPieceRecordTypeService;
@Override
public List<NotePiecePrompt> listPiecePromptBySplitId(NoteRecordSplitPieceSentence noteRecordSplitPieceSentence) {
List<NotePiecePrompt> notePromptList = new ArrayList<>();
// 同语义片段是否为空
if (null == noteRecordSplitPieceSentence) {
log.warn("listPiecePromptBySplitId根据同语义片段id{}未找到切分笔录数据...", noteRecordSplitPieceSentence.getId());
return notePromptList;
}
// 查询同语义片段分类
String recordType = noteRecordSplitPieceSentence.getContentChuckSummary();
if (StrUtil.isBlank(recordType)) {
log.info("listPiecePromptBySplitId:同语义片段:{} 不属于任何分类...", noteRecordSplitPieceSentence.getId());
return notePromptList;
}
// todo 这里是用全部分类还是用当前笔录生成的分类,暂定全部分类
// 获取所有的分类
List<ModelPieceRecordType> allTypeList = modelPieceRecordTypeService
.lambdaQuery()
.select(ModelPieceRecordType::getId, ModelPieceRecordType::getRecordType)
.list();
Map<String, String> allTypeMap = allTypeList.stream().collect(Collectors.toMap(ModelPieceRecordType::getRecordType, ModelPieceRecordType::getId, (k1, k2) -> k1));
// 对切分后的笔录进行遍历
String[] split = recordType.split(";");
for (String typeName : split) {
String typeId = allTypeMap.get(typeName);
if (null == typeId) {
log.info("listPiecePromptBySplitId:同语义片段id:{} typeName:{}未在全局分类中找到数据...", noteRecordSplitPieceSentence.getId(), typeName);
continue;
}
// 根据同语义类型找到所有的提取三元组的提示词
// 一个提示词可能关联多个类型,要进行拆分操作
List<NotePiecePromptTypeRel> promptTypeRelList = notePiecePromptTypeRelService.lambdaQuery().eq(NotePiecePromptTypeRel::getTypeId, typeId).select(NotePiecePromptTypeRel::getPromptId).list();
if (CollUtil.isEmpty(promptTypeRelList)) {
log.info("listPiecePromptBySplitId:同语义片段:{}根据typeId:{},typeName:{},未找到对应的提示词信息...", noteRecordSplitPieceSentence.getId(), typeId, typeName);
continue;
}
List<String> promptIdList = promptTypeRelList.stream().map(NotePiecePromptTypeRel::getPromptId).toList();
List<NotePiecePrompt> list = super.lambdaQuery().in(NotePiecePrompt::getId, promptIdList).list();
if (CollUtil.isEmpty(list)) {
log.info("listPiecePromptBySplitId:根据 promptIdList:{},未找到对应的提示词信息...", CollUtil.join(promptIdList, ","));
continue;
}
notePromptList.addAll(list);
}
return notePromptList;
}
}

@ -0,0 +1,20 @@
package com.supervision.police.service.impl;
import com.supervision.police.domain.NotePiecePromptTypeRel;
import com.supervision.police.mapper.NotePiecePromptTypeRelMapper;
import com.supervision.police.service.NotePiecePromptTypeRelService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Service
public class NotePiecePromptTypeRelServiceImpl extends ServiceImpl<NotePiecePromptTypeRelMapper, NotePiecePromptTypeRel> implements NotePiecePromptTypeRelService {
}

@ -0,0 +1,20 @@
package com.supervision.police.service.impl;
import com.supervision.police.domain.NoteRecordSplitPieceSentence;
import com.supervision.police.mapper.NoteRecordSplitPieceSentenceMapper;
import com.supervision.police.service.NoteRecordSplitPieceSentenceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-11
*/
@Service
public class NoteRecordSplitPieceSentenceServiceImpl extends ServiceImpl<NoteRecordSplitPieceSentenceMapper, NoteRecordSplitPieceSentence> implements NoteRecordSplitPieceSentenceService {
}

@ -0,0 +1,42 @@
package com.supervision.police.service.impl;
import com.supervision.police.domain.NoteRecordSplitSentence;
import com.supervision.police.mapper.NoteRecordSplitSentenceMapper;
import com.supervision.police.service.NoteRecordSplitSentenceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-10
*/
@Service
public class NoteRecordSplitSentenceServiceImpl extends ServiceImpl<NoteRecordSplitSentenceMapper, NoteRecordSplitSentence> implements NoteRecordSplitSentenceService {
/**
*
* @param noteRecordSplitList
*/
@Override
public void saveBatchList(List<NoteRecordSplitSentence> noteRecordSplitList) {
this.baseMapper.saveBatchList(noteRecordSplitList);
}
/**
* llmGenA
* @param ids id
* @param noteRecordSplitPieceSentences id
*/
@Override
public void updateBatchList(List<Long> ids,Long noteRecordSplitPieceSentences){
this.baseMapper.updateBatchList(ids,noteRecordSplitPieceSentences);
}
}

@ -0,0 +1,20 @@
package com.supervision.police.service.impl;
import com.supervision.police.domain.PieceTripleInfo;
import com.supervision.police.mapper.PieceTripleInfoMapper;
import com.supervision.police.service.PieceTripleInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Service
public class PieceTripleInfoServiceImpl extends ServiceImpl<PieceTripleInfoMapper, PieceTripleInfo> implements PieceTripleInfoService {
}

@ -0,0 +1,178 @@
package com.supervision.thread;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.supervision.constant.PromptsEnum;
import com.supervision.police.domain.*;
import com.supervision.police.dto.LongTextSingleSentenceSummaryDto;
import com.supervision.police.dto.PieceSentenceIdDto;
import com.supervision.utils.UserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.ollama.OllamaChatClient;
import org.springframework.util.StopWatch;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Consumer;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Slf4j
public class LongTextTask implements Callable<Map<String, Object>> {
private final LongTextSingleSentenceSummaryDto longTextSingleSentenceSummaryDto;
private final OllamaChatClient chatClient;
private final Consumer<Map<String, Object>> consumer;
public LongTextTask(OllamaChatClient chatClient, LongTextSingleSentenceSummaryDto longTextSingleSentenceSummaryDto, Consumer<Map<String, Object>> consumer) {
this.longTextSingleSentenceSummaryDto = longTextSingleSentenceSummaryDto;
this.chatClient = chatClient;
this.consumer = consumer;
}
@Override
public Map<String, Object> call() throws Exception {
return pieceSentenceNormal(longTextSingleSentenceSummaryDto);
}
/**
*
*
* @param longTextSingleSentenceSummaryDto
*/
private Map<String, Object> pieceSentenceNormal(LongTextSingleSentenceSummaryDto longTextSingleSentenceSummaryDto) throws Exception {
log.info("[QaAnswerLongTextTripletExtraction-Pool-PieceSentenceNormal]开始同语义归纳方法,当前线程是:{}", Thread.currentThread().getName());
Map<String, Object> map = new HashMap<>();
// 同语义集合
List<NoteRecordSplitPieceSentence> recordSplitPieceSentences = new ArrayList<>();
// 同语义使用单句id集合
List<PieceSentenceIdDto> noteRecordSplitPieceSentenceBySingle = new ArrayList<>();
// 笔录片段id
String noteRecordSplitId = longTextSingleSentenceSummaryDto.getNoteRecordSplitId();
// 单语句集合
List<NoteRecordSplitSentence> noteRecordSplitSentences = longTextSingleSentenceSummaryDto.getNoteRecordSplitSentences();
int noteRecordSplitSentencesSize = noteRecordSplitSentences.size();
// 获取末尾单句 N+1
NoteRecordSplitSentence endCombinedSentence = noteRecordSplitSentences.get(noteRecordSplitSentencesSize - 1);
Long endCombinedSentenceId = endCombinedSentence.getId();
ConcurrentLinkedDeque<Long> noteRecordSplitPieceSentenceDeque = new ConcurrentLinkedDeque<>();
noteRecordSplitPieceSentenceDeque.add(endCombinedSentenceId);
ConcurrentLinkedDeque<String> endCombinedSentenceDeque = new ConcurrentLinkedDeque<>();
endCombinedSentenceDeque.addLast(endCombinedSentence.getAnswer());
// 遍历单句集合
for (int i = noteRecordSplitSentencesSize - 2; i >= 0; i--) {
PieceSentenceIdDto pieceSentenceIdDto = new PieceSentenceIdDto();
// 获取第N句
NoteRecordSplitSentence currentSentence = noteRecordSplitSentences.get(i);
Long currentSentenceId = currentSentence.getId();
String currentSentenceAnswer = currentSentence.getAnswer();
// 对比句子语义
boolean inductionFlag = chatAiLongTextHomoSemanticInduction(String.valueOf(endCombinedSentenceDeque), currentSentenceAnswer);
if (inductionFlag) {
endCombinedSentenceDeque.addFirst(currentSentenceAnswer);
noteRecordSplitPieceSentenceDeque.addFirst(currentSentenceId);
} else {
NoteRecordSplitPieceSentence pieceSentence = setNotePieceRecordSentence(noteRecordSplitId, endCombinedSentenceDeque);
endCombinedSentenceDeque.remove();
endCombinedSentenceDeque.addLast(currentSentenceAnswer);
List<Long> longList = noteRecordSplitPieceSentenceDeque.stream().toList();
noteRecordSplitPieceSentenceDeque.remove();
noteRecordSplitPieceSentenceDeque.addLast(currentSentenceId);
pieceSentenceIdDto.setNoteRecordSplitPieceSentenceId(pieceSentence.getId());
pieceSentenceIdDto.setNoteRecordSplitSentenceId(longList);
recordSplitPieceSentences.add(pieceSentence);
noteRecordSplitPieceSentenceBySingle.add(pieceSentenceIdDto);
}
}
NoteRecordSplitPieceSentence pieceSentence = setNotePieceRecordSentence(noteRecordSplitId, endCombinedSentenceDeque);
recordSplitPieceSentences.add(pieceSentence);
noteRecordSplitPieceSentenceBySingle.add(new PieceSentenceIdDto(pieceSentence.getId(), noteRecordSplitPieceSentenceDeque.stream().toList()));
map.put("recordSplitPieceSentences", recordSplitPieceSentences);
map.put("noteRecordSplitPieceSentenceBySingle", noteRecordSplitPieceSentenceBySingle);
consumer.accept(map);
log.info("[QaAnswerLongTextTripletExtraction-Pool-PieceSentenceNormal]同语义归纳结束,当前线程是:{}", Thread.currentThread().getName());
return map;
}
/**
* @param encCombinedSentence N+1
* @param currentSentence N
* @return
*/
private boolean chatAiLongTextHomoSemanticInduction(String encCombinedSentence, String currentSentence) {
StopWatch stopWatch = new StopWatch();
// 分析同语义集合
stopWatch.start();
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("encCombinedSentence", encCombinedSentence);
paramMap.put("currentSentence", currentSentence);
String format = StrUtil.format(PromptsEnum.LONG_TEXT_SINGLE_STATEMENT_WITH_SEMANTIC_JUDGMENT_PROMPT_WORD.getContent(), paramMap);
ChatResponse call = chatClient.call(new Prompt(new UserMessage(format)));
stopWatch.stop();
String content = call.getResult().getOutput().getContent();
JSONObject jsonObject = JSON.parseObject(content);
boolean result = (boolean) jsonObject.get("result");
return result;
}
/**
*
*
* @param noteRecordSplitId id
* @param endSentenceDequeStringDeque
* @return
*/
public NoteRecordSplitPieceSentence setNotePieceRecordSentence(String noteRecordSplitId, ConcurrentLinkedDeque<String> endSentenceDequeStringDeque) {
StringBuilder endSentenceDequeStringBuilder = new StringBuilder();
for (String endSentenceDeque : endSentenceDequeStringDeque) {
endSentenceDequeStringBuilder.append(endSentenceDeque);
}
String endSentenceDequeStringBuilderString = String.valueOf(endSentenceDequeStringBuilder);
String noteRecordSplitPieceSentenceId = DefaultIdentifierGenerator.getInstance().nextId(null).toString();
NoteRecordSplitPieceSentence noteRecordSplitPieceSentence = new NoteRecordSplitPieceSentence();
noteRecordSplitPieceSentence.setId(noteRecordSplitPieceSentenceId);
noteRecordSplitPieceSentence.setCreateUserId(UserUtil.getUser().getId());
noteRecordSplitPieceSentence.setUpdateUserId(UserUtil.getUser().getId());
noteRecordSplitPieceSentence.setRecordSplitId(noteRecordSplitId);
noteRecordSplitPieceSentence.setContentChuck(endSentenceDequeStringBuilderString);
return noteRecordSplitPieceSentence;
}
}

@ -0,0 +1,30 @@
package com.supervision.thread;
import cn.hutool.core.thread.ThreadUtil;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线
*/
@Slf4j
@Component
public class LongtextThreadPool {
@Value("${fu-hsi-config.thread-pool.type.core:2}")
private int core;
public static ThreadPoolExecutor executorService;
@PostConstruct
public void init() {
log.info("LongtextThreadPool线程池初始化。线程数{}", core);
executorService = new ThreadPoolExecutor(1, 10000, 100L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
}
}

@ -0,0 +1,154 @@
package com.supervision.thread;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.supervision.police.domain.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.ollama.OllamaChatClient;
import org.springframework.util.StopWatch;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Callable;
/**
* <p>
*
* </p>
*
* @author longbao
* @since 2024-12-12
*/
@Slf4j
public class PieceTripleExtractTask implements Callable<PieceTripleInfo> {
private static final String HEAD_ENTITY_TYPE_ACTOR = "行为人";
private final NotePiecePrompt notePiecePrompt;
private final NoteRecordSplitPieceSentence noteRecordSplitPieceSentence;
private final CasePerson mainActor;
private final OllamaChatClient chatClient;
public PieceTripleExtractTask(OllamaChatClient chatClient,
CasePerson mainActor,
NotePiecePrompt notePiecePrompt,
NoteRecordSplitPieceSentence noteRecordSplitPieceSentence) {
this.chatClient = chatClient;
this.mainActor = mainActor;
this.notePiecePrompt = notePiecePrompt;
this.noteRecordSplitPieceSentence = noteRecordSplitPieceSentence;
}
/**
*
*
* @return
*/
@Override
public PieceTripleInfo call() throws Exception {
TripleRecord tripleRecord = chat4Triple(mainActor, notePiecePrompt, noteRecordSplitPieceSentence);
// 获取从提示词中提取到的三元组信息
TripleExtractResult extractResult = JSONUtil.toBean(tripleRecord.answer, TripleExtractResult.class);
if (ObjectUtil.isEmpty(extractResult) || CollUtil.isEmpty(extractResult.getResult())) {
log.warn("[QaAnswerLongTextTripletExtraction-call]提取三元组信息为空,忽略.提取的内容为:{}", tripleRecord.answer);
return null;
}
for (TripleExtractNode tripleExtractNode : extractResult.getResult()) {
TripleEntity headEntity = tripleExtractNode.getHeadEntity();
TripleEntity tailEntity = tripleExtractNode.getTailEntity();
String relation = tripleExtractNode.getRelation();
if (StrUtil.hasEmpty(headEntity.getName(), relation, tailEntity.getName())) {
log.warn("[QaAnswerLongTextTripletExtraction-call]提取三元组信息出现空值,忽略,主体:{},关系:{},客体:{}", headEntity.getName(), relation, tailEntity.getName());
return null;
}
// 构建三元组信息
PieceTripleInfo tripleInfo = new PieceTripleInfo();
tripleInfo.setId(DefaultIdentifierGenerator.getInstance().nextId(null).toString());
tripleInfo.setStartNode(headEntity.getName());
tripleInfo.setEndNode(tailEntity.getName());
tripleInfo.setRelation(relation);
tripleInfo.setPieceRecordSplitId(noteRecordSplitPieceSentence.getId());
tripleInfo.setRecordSplitId(noteRecordSplitPieceSentence.getRecordSplitId());
tripleInfo.setSubmitPrompt(tripleRecord.question);
tripleInfo.setStartNodeType(notePiecePrompt.getStartEntityType());
tripleInfo.setEndNodeType(notePiecePrompt.getEndEntityType());
return tripleInfo;
}
return null;
}
/**
* ollama
*
* @param mainActor
* @param prompt
* @param noteRecordSplitPieceSentence
* @return
*/
private TripleRecord chat4Triple(CasePerson mainActor, NotePiecePrompt prompt, NoteRecordSplitPieceSentence noteRecordSplitPieceSentence) {
String pieceSentenceContentChuck = noteRecordSplitPieceSentence.getContentChuck();
StopWatch stopWatch = new StopWatch();
// 分析三元组
stopWatch.start();
HashMap<String, String> paramMap = new HashMap<>();
paramMap.put("headEntityType", prompt.getStartEntityType());
paramMap.put("relation", prompt.getRelType());
paramMap.put("tailEntityType", prompt.getEndEntityType());
paramMap.put("contentChuckSummary", pieceSentenceContentChuck);
log.info("[QaAnswerLongTextTripletExtraction-call-chat4Triple]开始尝试提取三元组:{}-{}-{},mainActor:{}", prompt.getStartEntityType(), prompt.getRelType(), prompt.getEndEntityType(), mainActor == null ? "" : mainActor.getName());
if (mainActor != null && HEAD_ENTITY_TYPE_ACTOR.equals(prompt.getStartEntityType())) {
paramMap.put("requirement", "当前案件的行为人是" + mainActor.getName() + ",只尝试提取" + mainActor.getName() + "为头结点的三元组。");
} else {
paramMap.put("requirement", "");
}
String format = StrUtil.format(prompt.getPrompt(), paramMap);
log.info("[QaAnswerLongTextTripletExtraction-call-chat4Triple]三元组提取提示词:{}", format);
ChatResponse call = chatClient.call(new Prompt(new UserMessage(format)));
stopWatch.stop();
String content = call.getResult().getOutput().getContent();
log.info("问题:{}耗时:{},三元组提取结果是:{}", pieceSentenceContentChuck, stopWatch.getTotalTimeSeconds(), content);
return new TripleRecord(format, content);
}
record TripleRecord(String question, String answer) {
}
@Data
public static class TripleExtractResult {
private List<TripleExtractNode> result;
}
@Data
public static class TripleExtractNode {
private TripleEntity headEntity;
private String relation;
private TripleEntity tailEntity;
}
@Data
public static class TripleEntity {
private String name;
private String type;
}
}

@ -0,0 +1,30 @@
package com.supervision.thread;
import cn.hutool.core.thread.ThreadUtil;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线
*/
@Slf4j
@Component
public class PieceTripleThreadPool {
@Value("${fu-hsi-config.thread-pool.type.core:2}")
private int core;
public static ThreadPoolExecutor executorService;
@PostConstruct
public void init() {
log.info("LongtextThreadPool线程池初始化。线程数{}", core);
executorService = new ThreadPoolExecutor(1, 10000, 100L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
}
}

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.supervision.police.mapper.ModelPieceRecordTypeMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.supervision.police.domain.ModelPieceRecordType">
<id column="id" property="id" />
<result column="record_type" property="recordType" />
<result column="create_user_id" property="createUserId" />
<result column="create_time" property="createTime" />
<result column="update_user_id" property="updateUserId" />
<result column="update_time" property="updateTime" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, record_type, create_user_id, create_time, update_user_id, update_time
</sql>
</mapper>

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.supervision.police.mapper.NotePiecePromptMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.supervision.police.domain.NotePiecePrompt">
<id column="id" property="id"/>
<result column="prompt" property="prompt"/>
<result column="start_entity_type" property="startEntityType"/>
<result column="start_entity_template" property="startEntityTemplate"/>
<result column="rel_type" property="relType"/>
<result column="rel_template" property="relTemplate"/>
<result column="name" property="name"/>
<result column="end_entity_type" property="endEntityType"/>
<result column="end_entity_template" property="endEntityTemplate"/>
<result column="create_user_id" property="createUserId"/>
<result column="create_time" property="createTime"/>
<result column="update_user_id" property="updateUserId"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id
, prompt, start_entity_type, start_entity_template, rel_type, rel_template,name, end_entity_type, end_entity_template, create_user_id, create_time, update_user_id, update_time
</sql>
</mapper>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.supervision.police.mapper.NotePiecePromptTypeRelMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.supervision.police.domain.NotePiecePromptTypeRel">
<id column="id" property="id" />
<result column="prompt_id" property="promptId" />
<result column="type_id" property="typeId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, prompt_id, type_id
</sql>
</mapper>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.supervision.police.mapper.NoteRecordSplitPieceSentenceMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.supervision.police.domain.NoteRecordSplitPieceSentence">
<id column="id" property="id" />
<result column="record_split_id" property="recordSplitId" />
<!-- <result column="content_chuck" property="contentChuck" jdbcType="ARRAY"-->
<!-- typeHandler="com.supervision.handler.StringListTypeHandler"/>-->
<result column="content_chuck" property="contentChuck" />
<result column="content_chuck_summary" property="contentChuckSummary" />
<result column="extend" property="extend" />
<result column="create_user_id" property="createUserId" />
<result column="create_time" property="createTime" />
<result column="update_user_id" property="updateUserId" />
<result column="update_time" property="updateTime" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, record_split_id, content_chuck, content_chuck_summary, extend, create_user_id, create_time, update_user_id, update_time
</sql>
</mapper>

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.supervision.police.mapper.NoteRecordSplitSentenceMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.supervision.police.domain.NoteRecordSplitSentence">
<id column="id" property="id"/>
<result column="record_split_id" property="recordSplitId"/>
<result column="piece_record_split_id" property="pieceRecordSplitId"/>
<result column="answer" property="answer"/>
<result column="llm_gen_a" property="llmGenA"/>
<result column="extend_one" property="extendOne"/>
<result column="create_user_id" property="createUserId"/>
<result column="create_time" property="createTime"/>
<result column="update_user_id" property="updateUserId"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id
, record_split_id, piece_record_split_id, answer, llm_gen_a, extend_one, create_user_id, create_time, update_user_id, update_time
</sql>
<insert id="saveBatchList" parameterType="java.util.List">
insert into note_record_split_sentence (record_split_id, answer,create_user_id,update_user_id)
values
<foreach collection="noteRecordSplitList" item="entity" index="index" separator=",">
(
#{entity.recordSplitId}, #{entity.answer},#{entity.createUserId},#{entity.updateUserId}
)
</foreach>
</insert>
<update id="updateBatchList" parameterType="map">
UPDATE note_record_split_sentence
SET piece_record_split_id = #{noteRecordSplitPieceSentences}
WHERE id IN
<foreach item="id" index="index" collection="ids" open="(" separator="," close=")">
#{id}
</foreach>
</update>
</mapper>

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.supervision.police.mapper.PieceTripleInfoMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.supervision.police.domain.PieceTripleInfo">
<id column="id" property="id" />
<result column="start_node" property="startNode" />
<result column="end_node" property="endNode" />
<result column="relation" property="relation" />
<result column="record_split_id" property="recordSplitId" />
<result column="piece_record_split_id" property="pieceRecordSplitId" />
<result column="submit_prompt" property="submitPrompt" />
<result column="add_neo4j" property="addNeo4j" />
<result column="create_time" property="createTime" />
<result column="start_node_graph_id" property="startNodeGraphId" />
<result column="rel_graph_id" property="relGraphId" />
<result column="end_node_graph_id" property="endNodeGraphId" />
<result column="start_node_type" property="startNodeType" />
<result column="end_node_type" property="endNodeType" />
<result column="create_user_id" property="createUserId" />
<result column="update_user_id" property="updateUserId" />
<result column="update_time" property="updateTime" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, start_node, end_node, relation, record_split_id, piece_record_split_id, submit_prompt, add_neo4j, create_time, start_node_graph_id, rel_graph_id, end_node_graph_id, start_node_type, end_node_type, create_user_id, update_user_id, update_time
</sql>
</mapper>
Loading…
Cancel
Save