GenerateInstructionService.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. package cn.cslg.pas.service.dify;
  2. import cn.cslg.pas.common.model.dify.*;
  3. import cn.cslg.pas.common.model.dify.confessionSession.AddConfessionSessionDTO;
  4. import cn.cslg.pas.common.utils.ClaimUtils.ClaimSplitUtils;
  5. import cn.cslg.pas.common.utils.DateUtils;
  6. import cn.cslg.pas.common.utils.FileUtils;
  7. import cn.cslg.pas.common.utils.StringUtils;
  8. import cn.cslg.pas.common.vo.PatentRightParams;
  9. import cn.cslg.pas.common.vo.RePatentClaim;
  10. import cn.cslg.pas.domain.business.ReportProject;
  11. import cn.cslg.pas.domain.business.ReportTemple;
  12. import cn.cslg.pas.domain.dify.AssoConfessionSessionFile;
  13. import cn.cslg.pas.domain.dify.ConfessionSession;
  14. import cn.cslg.pas.exception.ExceptionEnum;
  15. import cn.cslg.pas.exception.XiaoShiException;
  16. import cn.cslg.pas.service.business.ReportTempleService;
  17. import cn.cslg.pas.service.common.DifyService;
  18. import cn.cslg.pas.service.common.FileManagerService;
  19. import cn.hutool.core.util.IdUtil;
  20. import com.alibaba.fastjson.JSONArray;
  21. import com.alibaba.fastjson.JSONObject;
  22. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  23. import com.deepoove.poi.XWPFTemplate;
  24. import com.deepoove.poi.config.Configure;
  25. import com.google.gson.Gson;
  26. import okhttp3.MediaType;
  27. import okhttp3.OkHttpClient;
  28. import okhttp3.Request;
  29. import okhttp3.RequestBody;
  30. import org.springframework.beans.factory.annotation.Autowired;
  31. import org.springframework.beans.factory.annotation.Value;
  32. import org.springframework.stereotype.Service;
  33. import reactor.core.publisher.Flux;
  34. import reactor.core.publisher.FluxSink;
  35. import java.io.File;
  36. import java.io.IOException;
  37. import java.util.*;
  38. import java.util.concurrent.TimeUnit;
  39. import java.util.regex.Matcher;
  40. import java.util.regex.Pattern;
  41. import java.util.stream.Collectors;
  42. @Service
  43. public class GenerateInstructionService {
  44. @Autowired
  45. private ReportTempleService templeService;
  46. @Autowired
  47. private FileUtils fileUtils;
  48. @Autowired
  49. private AssoConfessionSessionFileService assoConfessionSessionFileService;
  50. @Autowired
  51. private DifyService difyService;
  52. @Autowired
  53. private FileManagerService fileManagerService;
  54. @Autowired
  55. private ConfessionSessionService confessionSessionService;
  56. private final static String ALL_START = "all_start";
  57. private final static String ALL_END = "all_end";
  58. private final static String START = "start";
  59. private final static String END = "end";
  60. private final static String MESSAGE = "message";
  61. private final static String FIELD_TITLE = "title";
  62. private final static String FIELD_TECHNICAL = "technical";
  63. private final static String FIELD_IMPLEMENTATION = "implementation";
  64. private final static String FIELD_BACKGROUND = "background";
  65. private final static String FIELD_CONTENT = "content";
  66. private final static String ERROR = "error";
  67. private Integer SESSION_ID;
  68. @Value("${DIFY.gInstructionKey}")
  69. private String gInstructionKey;
  70. public String getClaimContent(String claim) {
  71. claim= claim.replaceAll("所述","");
  72. // 正则表达式模式(注意 Java 中需要双反斜杠转义)
  73. String regex = "其特征在于[,。;!?、]+(.+)";
  74. Pattern pattern = Pattern.compile(regex);
  75. Matcher matcher = pattern.matcher(claim);
  76. if (matcher.find()) {
  77. // 提取第一个捕获组的内容(即括号内的部分)
  78. return matcher.group(1).trim();
  79. }
  80. return claim; // 未找到匹配时返回空字符串
  81. }
  82. public String getMainClaimContent(String claim) {
  83. claim= claim.replaceAll("所述","");
  84. // 正则表达式模式(注意 Java 中需要双反斜杠转义)
  85. claim= claim.replaceAll("^(\\d+[.、]|\\[[0-9]+])","");
  86. claim =claim.replaceAll("其特征在于[,。;!?、]","");
  87. return claim; // 未找到匹配时返回空字符串
  88. }
  89. public String getClaimText(String claim) {
  90. String combinedRegex = "^(\\d+[.、]|\\[[0-9]+])";
  91. String output = claim.replaceAll(combinedRegex, "").replaceAll("[\\n\\r]+$", "");
  92. return output; // 未找到匹配时返回空字符串
  93. }
  94. private XWPFTemplate getTemplate(Map<String, Object> map, String filePath) {
  95. //装载标的专利信息
  96. XWPFTemplate template = null;
  97. try {
  98. Configure configure = Configure.builder()
  99. .build();
  100. template = XWPFTemplate.compile(filePath, configure).render(map);
  101. } catch (Exception e) {
  102. e.printStackTrace();
  103. throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "未匹配到模版文件");
  104. }
  105. return template;
  106. }
  107. public Flux<String> generateInstruction2(GenerateClaimDTO generateClaimDTO) throws Exception {
  108. Integer templeId = 19;
  109. String claim = generateClaimDTO.getClaim();
  110. String background = generateClaimDTO.getBackground();
  111. Map<String, Object> addMap = new HashMap<>();
  112. Map<String, Object> queryMap = new HashMap<>();
  113. queryMap.put("claim", claim);
  114. queryMap.put("background", background);
  115. addMap.put("query", queryMap);
  116. String addStr = JSONObject.toJSONString(addMap);
  117. AddConfessionSessionDTO addConfessionSessionDTO = new AddConfessionSessionDTO();
  118. addConfessionSessionDTO.setType(3);
  119. addConfessionSessionDTO.setContent(addStr);
  120. ConfessionSession confessionSession = confessionSessionService.addSessionReDO(addConfessionSessionDTO);
  121. SESSION_ID = confessionSession.getId();
  122. ReportTemple reportTemplate = templeService.getById(templeId);
  123. String templateFilePath = fileUtils.getPath(reportTemplate.getTemplatePath());
  124. Map<String, Object> map = new HashMap<>();
  125. return Flux.create(emitter -> {
  126. new Thread(() -> {
  127. try {
  128. //;流程开始
  129. String startMess = getFluxMessage("", ALL_START, "");
  130. emitter.next(startMess);
  131. PatentRightParams params = new PatentRightParams();
  132. params.setCountry("CN");
  133. params.setContent(claim);
  134. params.setPatentNo("CN");
  135. List<RePatentClaim> rePatentClaims = ClaimSplitUtils.formatPatentRight(params);
  136. //生成标题和技术领域
  137. GenerateInstructAnswerVO generateInstructAnswerVO = this.genrateTechcialAndTitle(emitter, claim, background);
  138. String conversionId = generateInstructAnswerVO.getConversionId();
  139. String title = generateInstructAnswerVO.getTitle();
  140. String technical = generateInstructAnswerVO.getTechnical();
  141. map.put("title", title);
  142. map.put("conversionId", conversionId);
  143. map.put("technical", technical);
  144. //生成背景技术
  145. GenerateInstructAnswerVO generateInstructAnswerVO4 = this.generateBackGround(emitter, background);
  146. map.put("background", generateInstructAnswerVO4.getAnswers());
  147. //更新会话
  148. String name = DateUtils.dateTimeToStr(new Date(), "yyyyMMdd");
  149. name = name + "-" + title + "-生成说明书";
  150. confessionSession.setConversationName(name);
  151. confessionSession.setConversationId(conversionId);
  152. confessionSession.updateById();
  153. //生成发明内容
  154. String startMessage = getFluxMessage(FIELD_CONTENT, START, "");
  155. emitter.next(startMessage);
  156. ClaimExplainVO claimExplainVO = this.getFirstImplementation(rePatentClaims.get(0), background, conversionId);
  157. GenerateInstructAnswerVO generateInstructAnswerVO3 = this.generateContent(emitter, rePatentClaims, claimExplainVO);
  158. map.put("content",generateInstructAnswerVO3.getAnswers());
  159. //生成具体实施方式
  160. GenerateInstructAnswerVO generateInstructAnswerVO2 = this.generateImplementation(emitter, claimExplainVO, background, conversionId, rePatentClaims);
  161. map.put("implementation", generateInstructAnswerVO2.getImplementations());
  162. //生成文档
  163. String fileGuid = this.generateFile(map, templateFilePath, name);
  164. AssoConfessionSessionFile assoConfessionSessionFile = new AssoConfessionSessionFile();
  165. assoConfessionSessionFile.setGuid(fileGuid);
  166. assoConfessionSessionFile.setConfessionSessionId(confessionSession.getId());
  167. assoConfessionSessionFile.insert();
  168. String endMess = getFluxMessage("", ALL_END, fileGuid);
  169. emitter.next(endMess);
  170. } catch (Exception e) {
  171. e.printStackTrace();
  172. } finally {
  173. emitter.complete();
  174. }
  175. }).start();
  176. });
  177. }
  178. /**
  179. * 生成文件
  180. *
  181. * @param map
  182. * @param templateFilePath
  183. * @param name
  184. * @return
  185. * @throws Exception
  186. */
  187. public String generateFile(Map<String, Object> map, String templateFilePath, String name) throws Exception {
  188. XWPFTemplate xwpfTemplate = this.getTemplate(map, templateFilePath);
  189. String fileName = name + ".docx";
  190. String directoryName = fileUtils.createDirectory();
  191. String outPath = fileUtils.getSavePath(directoryName) + fileName;
  192. File file = new File(outPath);
  193. // 生成word保存在指定目录
  194. xwpfTemplate.writeToFile(outPath);
  195. xwpfTemplate.close();
  196. List<String> ids = fileManagerService.uploadFileGetGuid2(Arrays.asList(file));
  197. if (ids == null || ids.size() == 0) {
  198. throw new XiaoShiException("保存记录失败");
  199. }
  200. return ids.get(0);
  201. }
  202. /**
  203. * 生成标题和技术领域
  204. *
  205. * @param fluxSink
  206. * @param claim
  207. * @param background
  208. * @return
  209. * @throws Exception
  210. */
  211. public GenerateInstructAnswerVO genrateTechcialAndTitle(FluxSink fluxSink, String claim, String background) throws Exception {
  212. GenerateInstructAnswerVO generateInstructAnswerVO = null;
  213. GenerateTechnicalVO generateTechnicalVO = null;
  214. String startMessage = getFluxMessage(FIELD_TITLE, START, "");
  215. fluxSink.next(startMessage);
  216. Boolean ifError = false;
  217. try {
  218. generateInstructAnswerVO = this.getAnswerFromAI(claim, background, null, "g&technical", null);
  219. String answer = generateInstructAnswerVO.getAnswer();
  220. generateTechnicalVO = JSONObject.parseObject(answer, GenerateTechnicalVO.class);
  221. } catch (Exception e) {
  222. e.printStackTrace();
  223. ifError = true;
  224. }
  225. generateInstructAnswerVO.setTitle(generateTechnicalVO.getTitle());
  226. generateInstructAnswerVO.setTechnical(generateTechnicalVO.getTechnical());
  227. String message = "";
  228. if (ifError) {
  229. message = getFluxMessage(FIELD_TITLE, ERROR, "生成标题异常");
  230. } else {
  231. message = getFluxMessage(FIELD_TITLE, MESSAGE, generateTechnicalVO.getTitle());
  232. }
  233. fluxSink.next(message);
  234. String endMessage = getFluxMessage(FIELD_TITLE, END, "");
  235. fluxSink.next(endMessage);
  236. String startMessage2 = getFluxMessage(FIELD_TECHNICAL, START, "");
  237. fluxSink.next(startMessage2);
  238. String message2 = "";
  239. if (ifError) {
  240. message2 = getFluxMessage(FIELD_TECHNICAL, ERROR, "生成技术领域异常");
  241. } else {
  242. message2 = getFluxMessage(FIELD_TECHNICAL, MESSAGE, generateTechnicalVO.getTechnical());
  243. }
  244. fluxSink.next(message2);
  245. String endMessage2 = getFluxMessage(FIELD_TECHNICAL, END, "");
  246. fluxSink.next(endMessage2);
  247. return generateInstructAnswerVO;
  248. }
  249. /**
  250. * 生成第一个权利要求解释
  251. *
  252. * @param rePatentClaim
  253. * @return
  254. */
  255. public ClaimExplainVO getFirstImplementation(RePatentClaim rePatentClaim, String background, String conversationId) throws Exception {
  256. ClaimExplainVO claimExplainVO = null;
  257. try {
  258. String claimContent = rePatentClaim.getContent();
  259. GenerateInstructAnswerVO generateInstructAnswerVO = this.getAnswerFromAI(claimContent, background, 0, "g&implementation", conversationId);
  260. String answer = generateInstructAnswerVO.getAnswer();
  261. claimExplainVO = JSONObject.parseObject(answer, ClaimExplainVO.class);
  262. } catch (Exception e) {
  263. e.printStackTrace();
  264. }
  265. return claimExplainVO;
  266. }
  267. /**
  268. * 生成权要的具体实施方式
  269. *
  270. * @param fluxSink
  271. * @param firstClaimExplainVO
  272. * @param background
  273. * @param conversationId
  274. * @param rePatentClaims
  275. * @return
  276. * @throws Exception
  277. */
  278. public GenerateInstructAnswerVO generateImplementation(FluxSink fluxSink, ClaimExplainVO firstClaimExplainVO, String background, String conversationId, List<RePatentClaim> rePatentClaims) throws Exception {
  279. String startMessage = getFluxMessage(FIELD_IMPLEMENTATION, START, "");
  280. fluxSink.next(startMessage);
  281. GenerateInstructAnswerVO mainVO = new GenerateInstructAnswerVO();
  282. List<String> reContents = new ArrayList<>();
  283. for (int i = 0; i < rePatentClaims.size(); i++) {
  284. RePatentClaim rePatentClaim = rePatentClaims.get(i);
  285. ClaimExplainVO claimExplainVO = null;
  286. if (i == 0) {
  287. claimExplainVO = firstClaimExplainVO;
  288. } else {
  289. try {
  290. String claimContent = rePatentClaim.getContent();
  291. GenerateInstructAnswerVO generateInstructAnswerVO = this.getAnswerFromAI(claimContent, background, i, "g&implementation", conversationId);
  292. String answer = generateInstructAnswerVO.getAnswer();
  293. if (generateInstructAnswerVO.getConversionId() != null) {
  294. mainVO.setConversionId(generateInstructAnswerVO.getConversionId());
  295. }
  296. claimExplainVO = JSONObject.parseObject(answer, ClaimExplainVO.class);
  297. } catch (Exception e) {
  298. }
  299. }
  300. String message = "";
  301. String reStr = null;
  302. if (claimExplainVO != null) {
  303. List<String> contents = this.formatImplementation(claimExplainVO,rePatentClaim);
  304. if(contents.size()>0){
  305. reContents.addAll(contents);
  306. reStr = StringUtils.join(contents, "\n");
  307. }
  308. if (i != 0) {
  309. reStr = "\n" + reStr;
  310. }
  311. message = getFluxMessage(FIELD_IMPLEMENTATION, MESSAGE, reStr);
  312. } else {
  313. message = getFluxMessage(FIELD_IMPLEMENTATION, MESSAGE, "生成权要" + (i + 1) + "的具体实施方式异常");
  314. }
  315. fluxSink.next(message);
  316. }
  317. mainVO.setImplementations(reContents);
  318. String endMessage = getFluxMessage(FIELD_IMPLEMENTATION, END, "");
  319. fluxSink.next(endMessage);
  320. return mainVO;
  321. }
  322. /**
  323. * 生成单个权要的具体实施方式
  324. *
  325. * @param claimExplainVO
  326. * @return
  327. */
  328. private List<String> formatImplementation(ClaimExplainVO claimExplainVO,RePatentClaim rePatentClaim) {
  329. String reStr = null;
  330. List<String> contents = new ArrayList<>();
  331. String explainVOClaim = claimExplainVO.getClaim();
  332. String effect = claimExplainVO.getEffects();
  333. String explain = claimExplainVO.getExplain();
  334. if (explainVOClaim != null && !explainVOClaim.trim().equals("")) {
  335. String tem="";
  336. if (rePatentClaim != null && rePatentClaim.getType() != null && rePatentClaim.getType().equals(1)) {
  337. tem = this.getMainClaimContent(rePatentClaim.getContent());
  338. } else {
  339. tem = "在一实施方式中,"+this.getClaimContent(rePatentClaim.getContent());
  340. }
  341. contents.add(tem);
  342. }
  343. if (effect != null && !effect.trim().equals("")) {
  344. contents.add(effect);
  345. }
  346. if (explain != null && !explain.trim().equals("")) {
  347. contents.add(explain);
  348. }
  349. return contents;
  350. }
  351. private String getFluxMessage(String field, String event, String content) {
  352. FluxMessageVO fluxMessage = new FluxMessageVO();
  353. fluxMessage.setEvent(event);
  354. fluxMessage.setField(field);
  355. fluxMessage.setContent(content);
  356. fluxMessage.setId(SESSION_ID);
  357. String json = JSONObject.toJSONString(fluxMessage);
  358. return json;
  359. }
  360. public GenerateInstructAnswerVO getAnswerFromAI(String claim, String background, Integer index, String type, String conversationId) throws Exception {
  361. GenerateInstructAnswerVO generateInstructAnswerVO = new GenerateInstructAnswerVO();
  362. DifyChatMessageDTO difyChatMessageDTO = new DifyChatMessageDTO();
  363. difyChatMessageDTO.setUser("1");
  364. difyChatMessageDTO.setResponseMode("blocking");
  365. difyChatMessageDTO.setQuery(type);
  366. difyChatMessageDTO.setConversationId(conversationId);
  367. Map<String, Object> map = new HashMap<>();
  368. map.put("claim", claim);
  369. map.put("background", background);
  370. map.put("num_index", index);
  371. difyChatMessageDTO.setInputs(map);
  372. String re = difyService.chatMessage(difyChatMessageDTO, gInstructionKey);
  373. JSONObject jsonObject = JSONObject.parseObject(re);
  374. String answer = jsonObject.get("answer").toString();
  375. String conversionId = jsonObject.get("conversation_id").toString();
  376. generateInstructAnswerVO.setAnswer(answer);
  377. generateInstructAnswerVO.setConversionId(conversionId);
  378. return generateInstructAnswerVO;
  379. }
  380. /**
  381. * 生成背景技术
  382. *
  383. * @param fluxSink
  384. * @param background
  385. * @return
  386. */
  387. public GenerateInstructAnswerVO generateBackGround(FluxSink fluxSink, String background) {
  388. GenerateInstructAnswerVO generateInstructAnswerVO = new GenerateInstructAnswerVO();
  389. generateInstructAnswerVO.setAnswer(background);
  390. String startMessage = getFluxMessage(FIELD_BACKGROUND, START, "");
  391. fluxSink.next(startMessage);
  392. String message = getFluxMessage(FIELD_BACKGROUND, MESSAGE, background);
  393. fluxSink.next(message);
  394. String endMessage = getFluxMessage(FIELD_BACKGROUND, END, "");
  395. fluxSink.next(endMessage);
  396. List<String> answers =Arrays.asList( background.split("\n"));
  397. generateInstructAnswerVO.setAnswers(answers);
  398. return generateInstructAnswerVO;
  399. }
  400. /**
  401. * 生成发明/实用新型内容
  402. *
  403. * @param fluxSink
  404. * @param rePatentClaims
  405. * @return
  406. */
  407. public GenerateInstructAnswerVO generateContent(FluxSink fluxSink, List<RePatentClaim> rePatentClaims, ClaimExplainVO claimExplainVO) {
  408. GenerateInstructAnswerVO generateInstructAnswerVO = new GenerateInstructAnswerVO();
  409. List<String> contentStrs = new ArrayList<>();
  410. for (RePatentClaim rePatentClaim : rePatentClaims) {
  411. String claimContent = rePatentClaim.getContent();
  412. String temContent = "";
  413. if (rePatentClaim != null && rePatentClaim.getType() != null && rePatentClaim.getType().equals(1)) {
  414. temContent = this.getMainClaimContent(claimContent);
  415. } else {
  416. temContent = "其中,"+this.getClaimContent(claimContent);
  417. }
  418. contentStrs.add(temContent);
  419. }
  420. String reContent = "";
  421. if (contentStrs.size() != 0) {
  422. reContent = StringUtils.join(contentStrs, "\n");
  423. }
  424. String message = getFluxMessage(FIELD_CONTENT, MESSAGE, reContent);
  425. fluxSink.next(message);
  426. if (claimExplainVO != null) {
  427. String temContent="有益效果是:" + claimExplainVO.getEffects();
  428. contentStrs.add(temContent);
  429. message = getFluxMessage(FIELD_CONTENT, MESSAGE,"\n"+temContent);
  430. fluxSink.next(message);
  431. } else {
  432. message = getFluxMessage(FIELD_CONTENT, ERROR, "生成有益效果异常");
  433. fluxSink.next(message);
  434. }
  435. String endMessage = getFluxMessage(FIELD_CONTENT, END, "");
  436. fluxSink.next(endMessage);
  437. generateInstructAnswerVO.setAnswer(reContent);
  438. generateInstructAnswerVO.setAnswers(contentStrs);
  439. return generateInstructAnswerVO;
  440. }
  441. }