Browse Source

导入bean

rengb 4 years ago
parent
commit
7548b3a86c
100 changed files with 6611 additions and 18 deletions
  1. 5 0
      common/pom.xml
  2. 1 1
      common/src/main/java/com/lantone/config/MybatisPlusConfig.java
  3. 1 1
      common/src/main/java/com/lantone/config/SwaggerConfiguration.java
  4. 119 0
      common/src/main/java/com/lantone/common/util/CatalogueUtil.java
  5. 65 1
      common/src/main/java/com/lantone/util/DateUtil.java
  6. 1 1
      common/src/main/java/com/lantone/util/EnDecodeUtil.java
  7. 1 1
      common/src/main/java/com/lantone/util/EncrypDES.java
  8. 1 1
      common/src/main/java/com/lantone/util/ExcelUtil.java
  9. 1 1
      common/src/main/java/com/lantone/util/FastJsonUtils.java
  10. 1 1
      common/src/main/java/com/lantone/util/FileUtil.java
  11. 1 1
      common/src/main/java/com/lantone/util/GZIPUtils.java
  12. 1 1
      common/src/main/java/com/lantone/util/GsonUtil.java
  13. 1 1
      common/src/main/java/com/lantone/util/ListUtil.java
  14. 1 1
      common/src/main/java/com/lantone/util/ObjectUtil.java
  15. 42 1
      common/src/main/java/com/lantone/util/StringUtil.java
  16. 1 1
      common/src/main/java/com/lantone/util/UUidUtil.java
  17. 16 1
      config-center/src/main/resources/shared/structureCenter-debug.yml
  18. 16 1
      config-center/src/main/resources/shared/structureCenter-dev.yml
  19. 16 1
      config-center/src/main/resources/shared/structureCenter-local.yml
  20. 18 0
      config-center/src/main/resources/shared/structureCenter-master.yml
  21. 16 1
      config-center/src/main/resources/shared/structureCenter-test.yml
  22. 4 0
      structure-center/pom.xml
  23. 34 0
      structure-center/src/main/java/com/lantone/structure/ai/AIAnalyze.java
  24. 528 0
      structure-center/src/main/java/com/lantone/structure/ai/BeHospitalizedAI.java
  25. 92 0
      structure-center/src/main/java/com/lantone/structure/ai/ConsultationAI.java
  26. 261 0
      structure-center/src/main/java/com/lantone/structure/ai/FirstCourseRecordAI.java
  27. 152 0
      structure-center/src/main/java/com/lantone/structure/ai/LeaveHospitalAI.java
  28. 247 0
      structure-center/src/main/java/com/lantone/structure/ai/ModelAI.java
  29. 133 0
      structure-center/src/main/java/com/lantone/structure/ai/OperationAI.java
  30. 376 0
      structure-center/src/main/java/com/lantone/structure/ai/ThreeLevelWardAI.java
  31. 205 0
      structure-center/src/main/java/com/lantone/structure/ai/model/ConflictFinder.java
  32. 21 0
      structure-center/src/main/java/com/lantone/structure/ai/model/CrfOut.java
  33. 27 0
      structure-center/src/main/java/com/lantone/structure/ai/model/EntityBlock.java
  34. 267 0
      structure-center/src/main/java/com/lantone/structure/ai/model/EntityEnum.java
  35. 282 0
      structure-center/src/main/java/com/lantone/structure/ai/model/InvertedIndexTableBuilder.java
  36. 35 0
      structure-center/src/main/java/com/lantone/structure/ai/model/Lemma.java
  37. 19 0
      structure-center/src/main/java/com/lantone/structure/ai/model/Relation.java
  38. 394 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcess.java
  39. 143 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessClinic.java
  40. 39 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessDiag.java
  41. 89 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessDrug.java
  42. 175 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessFamily.java
  43. 40 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessGenerals.java
  44. 116 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessLeaveHospital.java
  45. 50 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessLis.java
  46. 70 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessMarital.java
  47. 127 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessMenses.java
  48. 140 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessOperationDiscussion.java
  49. 120 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessPacs.java
  50. 198 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessPast.java
  51. 138 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessPersonal.java
  52. 375 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessThreeLevelWard.java
  53. 64 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessTreatPlan.java
  54. 57 0
      structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessVital.java
  55. 23 0
      structure-center/src/main/java/com/lantone/structure/client/CRFServiceClient.java
  56. 23 0
      structure-center/src/main/java/com/lantone/structure/client/ChiefPresentSimilarityServiceClient.java
  57. 23 0
      structure-center/src/main/java/com/lantone/structure/client/NewSimilarityBatchServiceClient.java
  58. 23 0
      structure-center/src/main/java/com/lantone/structure/client/NewSimilarityServiceClient.java
  59. 23 0
      structure-center/src/main/java/com/lantone/structure/client/SimilarityServiceClient.java
  60. 10 0
      structure-center/src/main/java/com/lantone/structure/client/hystrix/CRFServiceHystrix.java
  61. 44 0
      structure-center/src/main/java/com/lantone/structure/controller/DbController.java
  62. 9 0
      structure-center/src/main/java/com/lantone/structure/dto/RespDTO.java
  63. 317 0
      structure-center/src/main/java/com/lantone/structure/model/Content.java
  64. 106 0
      structure-center/src/main/java/com/lantone/structure/model/InputInfo.java
  65. 28 0
      structure-center/src/main/java/com/lantone/structure/model/OutputInfo.java
  66. 10 0
      structure-center/src/main/java/com/lantone/structure/model/doc/AnesthesiaRelatedDoc.java
  67. 44 0
      structure-center/src/main/java/com/lantone/structure/model/doc/BeHospitalizedDoc.java
  68. 10 0
      structure-center/src/main/java/com/lantone/structure/model/doc/ClinicBloodEffectDoc.java
  69. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/ClinicalBloodDoc.java
  70. 14 0
      structure-center/src/main/java/com/lantone/structure/model/doc/CrisisInfoDoc.java
  71. 14 0
      structure-center/src/main/java/com/lantone/structure/model/doc/CrisisValueReportDoc.java
  72. 14 0
      structure-center/src/main/java/com/lantone/structure/model/doc/CriticallyIllNoticeDoc.java
  73. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/DailyCourseRecordDoc.java
  74. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/DeathCaseDiscussDoc.java
  75. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/DeathRecordDoc.java
  76. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/DifficultCaseDiscussDoc.java
  77. 14 0
      structure-center/src/main/java/com/lantone/structure/model/doc/DoctorAdviceDoc.java
  78. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/DutyShiftSystemDoc.java
  79. 28 0
      structure-center/src/main/java/com/lantone/structure/model/doc/FirstCourseRecordDoc.java
  80. 19 0
      structure-center/src/main/java/com/lantone/structure/model/doc/FirstPageRecordDoc.java
  81. 9 0
      structure-center/src/main/java/com/lantone/structure/model/doc/InformedConsentDoc.java
  82. 10 0
      structure-center/src/main/java/com/lantone/structure/model/doc/InvasiveOperationDoc.java
  83. 20 0
      structure-center/src/main/java/com/lantone/structure/model/doc/LeaveHospitalDoc.java
  84. 14 0
      structure-center/src/main/java/com/lantone/structure/model/doc/LisDoc.java
  85. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/MedicalRecordInfoDoc.java
  86. 10 0
      structure-center/src/main/java/com/lantone/structure/model/doc/MedicalWritingDoc.java
  87. 22 0
      structure-center/src/main/java/com/lantone/structure/model/doc/ModelDoc.java
  88. 17 0
      structure-center/src/main/java/com/lantone/structure/model/doc/NoticeOfConversationDoc.java
  89. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/NursingSystemDoc.java
  90. 14 0
      structure-center/src/main/java/com/lantone/structure/model/doc/PacsDoc.java
  91. 10 0
      structure-center/src/main/java/com/lantone/structure/model/doc/PathologyShipDoc.java
  92. 10 0
      structure-center/src/main/java/com/lantone/structure/model/doc/ReasonableDiagnosisDoc.java
  93. 15 0
      structure-center/src/main/java/com/lantone/structure/model/doc/RescueDoc.java
  94. 14 0
      structure-center/src/main/java/com/lantone/structure/model/doc/SeriouslyIllNoticeDoc.java
  95. 14 0
      structure-center/src/main/java/com/lantone/structure/model/doc/StagesSummaryDoc.java
  96. 121 0
      structure-center/src/main/java/com/lantone/structure/model/doc/ThreeLevelWardDoc.java
  97. 16 0
      structure-center/src/main/java/com/lantone/structure/model/doc/consultation/ConsultationApplicationDoc.java
  98. 20 0
      structure-center/src/main/java/com/lantone/structure/model/doc/consultation/ConsultationDoc.java
  99. 16 0
      structure-center/src/main/java/com/lantone/structure/model/doc/consultation/ConsultationRecordDoc.java
  100. 0 0
      structure-center/src/main/java/com/lantone/structure/model/doc/consultation/ConsultationResultsDoc.java

+ 5 - 0
common/pom.xml

@@ -74,6 +74,11 @@
             <artifactId>poi-ooxml</artifactId>
             <version>4.0.1</version>
         </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.9.3</version>
+        </dependency>
 
     </dependencies>
 

+ 1 - 1
common/src/main/java/com/lantone/config/MybatisPlusConfig.java

@@ -1,4 +1,4 @@
-package com.lantone.config;
+package com.lantone.common.config;
 
 import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
 import org.springframework.context.annotation.Bean;

+ 1 - 1
common/src/main/java/com/lantone/config/SwaggerConfiguration.java

@@ -1,4 +1,4 @@
-package com.lantone.config;
+package com.lantone.common.config;
 
 import com.github.xiaoymin.knife4j.spring.annotations.EnableSwaggerBootstrapUi;
 import com.google.common.collect.Lists;

+ 119 - 0
common/src/main/java/com/lantone/common/util/CatalogueUtil.java

@@ -0,0 +1,119 @@
+package com.lantone.common.util;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @ClassName : CatalogueUtil
+ * @Description :
+ * @Author : 楼辉荣
+ * @Date: 2020-03-09 10:59
+ */
+public class CatalogueUtil {
+
+    /**
+     * 拼接结构化数据
+     **/
+    public static String structureMapJoin(Map<String, String> structureMap, List<String> keys) {
+        String textJoin = "";
+        for (String key : keys) {
+            if (StringUtil.isNotBlank(structureMap.get(key))) {
+                textJoin += key + ":" + structureMap.get(key) + "\n";
+            }
+        }
+        return textJoin;
+    }
+
+    public static String removeSpecialChar(String content) {
+        if (StringUtil.isEmpty(content)) {
+            return "";
+        }
+        return content.replaceAll("[\r\n|\n|\t]", " ").trim();
+    }
+
+    /**
+     * 获取查房记录标题中医师职称
+     *
+     * @return
+     */
+    public static String subTitle(String srcText) {
+        String title = "";
+        if (StringUtil.isNotBlank(srcText)) {
+            //标题不包含代字,直接返回原标题
+            if (!srcText.contains("代")) {
+                return srcText;
+            }
+            //有携、兼字时,取携、兼字之前部分
+            if (srcText.contains("携")) {
+                title += srcText.substring(0, srcText.indexOf("携"));
+            } else if (srcText.contains("兼")) {
+                title += srcText.substring(0, srcText.indexOf("兼"));
+            }
+            //有代字时,取代字之后部分
+            if (srcText.contains("代") && srcText.indexOf("代") != srcText.length() - 1) {
+                title += srcText.substring(srcText.lastIndexOf("代") + 1);
+            } else {
+                return srcText;
+            }
+        }
+        return title;
+    }
+
+    /**
+     * 比较时间,以分钟为单位
+     * endDate比startDate多diff分钟则返回true
+     *
+     * @param startDate
+     * @param endDate
+     * @param diff
+     * @return
+     */
+    public static boolean compareTime(Date startDate, Date endDate, Long diff) {
+        boolean overtime = false;
+        if (startDate == null || endDate == null) {
+            return false;
+        }
+        Calendar calendar_s = Calendar.getInstance();
+        Calendar calendar_e = Calendar.getInstance();
+        Long time_s, time_e, time_diff;
+        try {
+            calendar_s.setTime(startDate);
+            calendar_e.setTime(endDate);
+
+            time_s = calendar_s.getTimeInMillis();
+            time_e = calendar_e.getTimeInMillis();
+
+            time_diff = (time_e - time_s) / (1000 * 60);
+            if (time_diff > diff) {
+                overtime = true;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return overtime;
+    }
+
+    public static String[] extractDigit(String value) {
+        String[] res = new String[2];
+        try {
+            String regTime = "([\\d]+)([\\u4e00-\\u9fa5]+)";
+            Pattern pattern = Pattern.compile(regTime);
+            Matcher matcher = pattern.matcher(value);
+            if (matcher.find(0)) {
+                res[0] = matcher.group(1);
+                res[1] = matcher.group(2);
+            } else {
+                res[0] = value;
+                res[1] = "";
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return res;
+    }
+
+}

+ 65 - 1
common/src/main/java/com/lantone/util/DateUtil.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -70,6 +70,70 @@ public class DateUtil {
      */
     public static String FORMAT_FULL_CN = "yyyy年MM月dd日  HH时mm分ss秒SSS毫秒";
 
+    public static String[] dateFormats = {
+            "yyyy年MM月dd日HH时mm分",
+            "yyyy年MM月dd日HH:mm",
+            "yyyy年MM月dd日H时mm分",
+            "yyyy年MM月dd日HH时m分",
+            "yyyy年MM月dd日H时m分",
+            "yyyy年M月dd日HH时mm分",
+            "yyyy年M月dd日H时mm分",
+            "yyyy年M月dd日HH时m分",
+            "yyyy年M月dd日H时m分",
+            "yyyy年MM月d日HH时mm分",
+            "yyyy年MM月d日H时mm分",
+            "yyyy年MM月d日HH时m分",
+            "yyyy年MM月d日H时m分",
+            "yyyy年M月d日HH时mm分",
+            "yyyy年M月d日H时mm分",
+            "yyyy年M月d日HH时m分",
+            "yyyy年M月d日H时m分",
+            "yyyy-MM-ddHH:mm:ss",
+            "yyyy-MM-ddHH:mm",
+            "yyyy-MM-ddHH:mm",
+            "yyyy-MM-ddHH:m",
+            "yyyy-MM-ddH:mm",
+            "yyyy-MM-ddH:m",
+            "yyyy-M-ddHH:mm",
+            "yyyy-M-ddHH:m",
+            "yyyy-M-ddH:mm",
+            "yyyy-M-ddH:m",
+            "yyyy-MM-dHH:mm",
+            "yyyy-MM-dHH:m",
+            "yyyy-MM-dH:mm",
+            "yyyy-MM-dH:m",
+            "yyyy-M-dHH:mm",
+            "yyyy-M-dHH:m",
+            "yyyy-M-dH:mm",
+            "yyyy-M-dH:m",
+            "yyyy-MM-dd",
+            "yyyy年MM月dd日H时",
+            "yyyy/MM/ddHH:mm:ss",
+            "yyyy/MM/ddHH:mm",
+            "yyyy/MM/ddHH:m",
+            "yyyy/MM/ddH:mm",
+            "yyyy/MM/ddH:m",
+            "yyyy/MM/ddHH:mm:",
+            "yyyy/M/ddHH:mm",
+            "yyyy/M/ddHH:m",
+            "yyyy/M/ddH:mm",
+            "yyyy/M/ddH:m",
+            "yyyy/MM/dHH:mm",
+            "yyyy/MM/dHH:m",
+            "yyyy/MM/dH:mm",
+            "yyyy/MM/dH:m",
+            "yyyy/M/dHH:mm",
+            "yyyy/M/dHH:m",
+            "yyyy/M/dH:mm",
+            "yyyy/M/dH:m",
+            "yyyy/MM/dd",
+            "yyyy.MM.dd",
+            "yyyy-MM-ddHH:mm:ss.000",
+            "yyyyMMddHH:mm",
+            "yyyy-MM-dd'T'HH:mm:ss",
+            "yyyy-MM-ddTHH:mm:ss",
+    };
+
 
     /**
      * Adds or subtracts the specified amount of time to the given calendar field, based on the calendar's rules. For

+ 1 - 1
common/src/main/java/com/lantone/util/EnDecodeUtil.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import sun.misc.BASE64Decoder;
 import sun.misc.BASE64Encoder;

+ 1 - 1
common/src/main/java/com/lantone/util/EncrypDES.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import org.apache.commons.codec.binary.Base64;
 

+ 1 - 1
common/src/main/java/com/lantone/util/ExcelUtil.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;

+ 1 - 1
common/src/main/java/com/lantone/util/FastJsonUtils.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;

+ 1 - 1
common/src/main/java/com/lantone/util/FileUtil.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import java.io.BufferedReader;
 import java.io.File;

+ 1 - 1
common/src/main/java/com/lantone/util/GZIPUtils.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;

+ 1 - 1
common/src/main/java/com/lantone/util/GsonUtil.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;

+ 1 - 1
common/src/main/java/com/lantone/util/ListUtil.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import java.util.ArrayList;
 import java.util.Collections;

+ 1 - 1
common/src/main/java/com/lantone/util/ObjectUtil.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import java.lang.reflect.Field;
 

+ 42 - 1
common/src/main/java/com/lantone/util/StringUtil.java

@@ -1,6 +1,10 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateUtils;
+
+import java.text.ParseException;
+import java.util.Date;
 
 /**
  * @Description: 字符串有关帮助类 封装了第三方帮助类
@@ -72,4 +76,41 @@ public class StringUtil {
         return str.replaceAll("[\\s\\p{Zs}]", "");
     }
 
+    /**
+     * 解析时间
+     *
+     * @param datetime
+     * @return
+     */
+    public static Date parseDateTime(String datetime) {
+        Date date = null;
+        try {
+            datetime = remove_ctl(datetime);
+
+            if (datetime.contains("至")) {
+                datetime = datetime.split("至")[1].replaceAll("[\\u4e00-\\u9fa5]", "");
+            }
+
+            if (datetime.length() > 0) {
+                date = DateUtils.parseDate(datetime, DateUtil.dateFormats);
+            }
+        } catch (ParseException ex) {
+            ex.printStackTrace();
+        }
+        return date;
+    }
+
+    /**
+     * 删除字符串中的换行和控制字符
+     *
+     * @param str
+     */
+    public static String remove_ctl(String str) {
+        String trim = "";
+        if(StringUtils.isNotEmpty(str)){
+            trim = str.replaceAll("\r|\n|\r\n|/r/n", "").trim();
+        }
+        return trim;
+    }
+
 }

+ 1 - 1
common/src/main/java/com/lantone/util/UUidUtil.java

@@ -1,4 +1,4 @@
-package com.lantone.util;
+package com.lantone.common.util;
 
 import java.util.UUID;
 

+ 16 - 1
config-center/src/main/resources/shared/structureCenter-debug.yml

@@ -1,3 +1,18 @@
 swagger.title: 数据后结构化服务
 swagger.des: 数据后结构化服务
-swagger.version: 0.0.1-SNAPSHOT
+swagger.version: 0.0.1-SNAPSHOT
+
+CRF:
+  url: http://192.168.2.234:3456/api/mr_info_ex/entity_predict
+
+Similarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/similarity
+
+NewSimilarity:
+  url: http://192.168.2.234:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.2.234:23232/api/similarity_batch
+
+ChiefPresentSimilarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 16 - 1
config-center/src/main/resources/shared/structureCenter-dev.yml

@@ -1,3 +1,18 @@
 swagger.title: 数据后结构化服务
 swagger.des: 数据后结构化服务
-swagger.version: 0.0.1-SNAPSHOT
+swagger.version: 0.0.1-SNAPSHOT
+
+CRF:
+  url: http://192.168.2.234:3456/api/mr_info_ex/entity_predict
+
+Similarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/similarity
+
+NewSimilarity:
+  url: http://192.168.2.234:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.2.234:23232/api/similarity_batch
+
+ChiefPresentSimilarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 16 - 1
config-center/src/main/resources/shared/structureCenter-local.yml

@@ -1,3 +1,18 @@
 swagger.title: 数据后结构化服务
 swagger.des: 数据后结构化服务
-swagger.version: 0.0.1-SNAPSHOT
+swagger.version: 0.0.1-SNAPSHOT
+
+CRF:
+  url: http://192.168.2.234:3456/api/mr_info_ex/entity_predict
+
+Similarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/similarity
+
+NewSimilarity:
+  url: http://192.168.2.234:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.2.234:23232/api/similarity_batch
+
+ChiefPresentSimilarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 18 - 0
config-center/src/main/resources/shared/structureCenter-master.yml

@@ -0,0 +1,18 @@
+swagger.title: 数据后结构化服务
+swagger.des: 数据后结构化服务
+swagger.version: 0.0.1-SNAPSHOT
+
+CRF:
+  url: http://192.168.2.234:3456/api/mr_info_ex/entity_predict
+
+Similarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/similarity
+
+NewSimilarity:
+  url: http://192.168.2.234:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.2.234:23232/api/similarity_batch
+
+ChiefPresentSimilarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 16 - 1
config-center/src/main/resources/shared/structureCenter-test.yml

@@ -1,3 +1,18 @@
 swagger.title: 数据后结构化服务
 swagger.des: 数据后结构化服务
-swagger.version: 0.0.1-SNAPSHOT
+swagger.version: 0.0.1-SNAPSHOT
+
+CRF:
+  url: http://192.168.2.234:3456/api/mr_info_ex/entity_predict
+
+Similarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/similarity
+
+NewSimilarity:
+  url: http://192.168.2.234:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.2.234:23232/api/similarity_batch
+
+ChiefPresentSimilarity:
+  url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 4 - 0
structure-center/pom.xml

@@ -32,6 +32,10 @@
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.projectlombok</groupId>

+ 34 - 0
structure-center/src/main/java/com/lantone/structure/ai/AIAnalyze.java

@@ -0,0 +1,34 @@
+package com.lantone.structure.ai;
+
+import com.lantone.structure.client.CRFServiceClient;
+import com.lantone.structure.client.SimilarityServiceClient;
+import com.lantone.structure.model.InputInfo;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class AIAnalyze {
+
+    private CRFServiceClient crfServiceClient;
+    private SimilarityServiceClient similarityServiceClient;
+    BeHospitalizedAI beHospitalizedAI = new BeHospitalizedAI();
+    FirstCourseRecordAI firstCourseRecordAI = new FirstCourseRecordAI();
+    LeaveHospitalAI leaveHospitalAI = new LeaveHospitalAI();
+    ThreeLevelWardAI threeLevelWardAI = new ThreeLevelWardAI();
+    OperationAI operationAI = new OperationAI();
+    ConsultationAI consultationAI = new ConsultationAI();
+
+    public AIAnalyze(CRFServiceClient crfService, SimilarityServiceClient similarityServiceClient) {
+        this.crfServiceClient = crfService;
+        this.similarityServiceClient = similarityServiceClient;
+    }
+
+    public void aiProcess(InputInfo inputInfo) {
+        beHospitalizedAI.medrec(inputInfo, crfServiceClient);
+        firstCourseRecordAI.medrec(inputInfo, crfServiceClient, similarityServiceClient);
+        leaveHospitalAI.medrec(inputInfo, crfServiceClient);
+        threeLevelWardAI.medrec(inputInfo, crfServiceClient);
+        operationAI.medrec(inputInfo, crfServiceClient);
+        consultationAI.medrec(inputInfo, crfServiceClient);
+    }
+
+}

+ 528 - 0
structure-center/src/main/java/com/lantone/structure/ai/BeHospitalizedAI.java

@@ -0,0 +1,528 @@
+package com.lantone.structure.ai;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.client.CRFServiceClient;
+import com.lantone.structure.ai.process.EntityProcessClinic;
+import com.lantone.structure.ai.process.EntityProcessDiag;
+import com.lantone.structure.ai.process.EntityProcessFamily;
+import com.lantone.structure.ai.process.EntityProcessLis;
+import com.lantone.structure.ai.process.EntityProcessMarital;
+import com.lantone.structure.ai.process.EntityProcessMenses;
+import com.lantone.structure.ai.process.EntityProcessPacs;
+import com.lantone.structure.ai.process.EntityProcessPast;
+import com.lantone.structure.ai.process.EntityProcessPersonal;
+import com.lantone.structure.ai.process.EntityProcessVital;
+import com.lantone.structure.model.Content;
+import com.lantone.structure.model.InputInfo;
+import com.lantone.structure.model.doc.BeHospitalizedDoc;
+import com.lantone.structure.model.entity.Diag;
+import com.lantone.structure.model.entity.Lis;
+import com.lantone.structure.model.entity.Pacs;
+import com.lantone.structure.model.entity.Vital;
+import com.lantone.structure.model.label.ChiefLabel;
+import com.lantone.structure.model.label.DiagLabel;
+import com.lantone.structure.model.label.FamilyLabel;
+import com.lantone.structure.model.label.MaritalLabel;
+import com.lantone.structure.model.label.MenstrualLabel;
+import com.lantone.structure.model.label.PacsLabel;
+import com.lantone.structure.model.label.PastLabel;
+import com.lantone.structure.model.label.PersonalLabel;
+import com.lantone.structure.model.label.PresentLabel;
+import com.lantone.common.util.FastJsonUtils;
+import com.lantone.common.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @ClassName : InHospitalDoc
+ * @Description :
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 18:58
+ */
+@Component
+public class BeHospitalizedAI extends ModelAI {
+    /**
+     * FirstCourseRecord_cx[病历首程]
+     * PastFamily_cx[既往史家族史]
+     * PersonalHistory_cx[个人史(月经史、婚育史)]
+     * HPIForCX_cx[主诉、现病史、专科检查]
+     * GeneralVital_cx[一般体格检查]
+     * chief_present[邵逸夫医院主诉]
+     * Diagnoses_cx[诊断]
+     * Present_cx[现病史]
+     * DiagnoseInAssistant[辅助检查]
+     */
+    public static List<String> medicalTextType = Arrays.asList("FirstCourseRecord_cx", "PastFamily_cx", "PersonalHistory_cx", "HPIForCX_cx",
+            "GeneralVital_cx", "chief_present", "Diagnoses_cx", "Present_cx", "DiagnoseInAssistant");
+    public static String entityRelationObject = "entity_relation_object";
+    public static String outputs = "outputs";
+
+    public void medrec(InputInfo inputInfo, CRFServiceClient crfServiceClient) {
+        JSONArray crfContent = new JSONArray();
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (beHospitalizedDoc != null) {
+            /* 主诉 */
+            if (beHospitalizedDoc.getChiefLabel() != null && beHospitalizedDoc.getChiefLabel().isCrfLabel()) {
+                String chiefText = beHospitalizedDoc.getChiefLabel().getText();
+                if (StringUtil.isNotBlank(chiefText)) {
+                    chiefText = "主诉:" + StringUtil.removeBlank(chiefText);//主诉入参 文本前需加 "主诉:"
+                    putContent(crfContent, medicalTextType.get(7), chiefText, Content.chief);/* 2020-06-08修改主诉模型为现病史模型 */
+                }
+            }
+            /* 现病史 */
+            if (beHospitalizedDoc.getPresentLabel() != null && beHospitalizedDoc.getPresentLabel().isCrfLabel()) {
+                String presentText = beHospitalizedDoc.getPresentLabel().getText();
+                putContent(crfContent, medicalTextType.get(7), presentText, Content.present);
+            }
+            /* 既往史 */
+            if (beHospitalizedDoc.getPastLabel() != null && beHospitalizedDoc.getPastLabel().isCrfLabel()) {
+                String pastText = beHospitalizedDoc.getPastLabel().getText();
+                putContent(crfContent, medicalTextType.get(1), pastText, Content.past);
+            }
+            /* 月经史文本需从个人史截取一部分文本拼接 */
+            String concatMenstrual = "";
+            /* 个人史 */
+            if (beHospitalizedDoc.getPersonalLabel() != null && beHospitalizedDoc.getPersonalLabel().isCrfLabel()) {
+                String personalText = beHospitalizedDoc.getPersonalLabel().getText();
+                putContent(crfContent, medicalTextType.get(2), personalText, Content.personal);
+                concatMenstrual = getConcatMenstrual(concatMenstrual, personalText);
+            }
+            /* 婚育史 */
+            if (beHospitalizedDoc.getMaritalLabel() != null && beHospitalizedDoc.getMaritalLabel().isCrfLabel()) {
+                String maritalText = beHospitalizedDoc.getMaritalLabel().getText();
+                putContent(crfContent, medicalTextType.get(2), maritalText, Content.marriage);
+            }
+            /* 月经史 */
+            if (beHospitalizedDoc.getMenstrualLabel() != null && beHospitalizedDoc.getMenstrualLabel().isCrfLabel()) {
+                String menstrualText = beHospitalizedDoc.getMenstrualLabel().getText();
+                putContent(crfContent, medicalTextType.get(2), concatMenstrual, menstrualText, Content.menses);
+            }
+            /* 家族史 */
+            if (beHospitalizedDoc.getFamilyLabel() != null && beHospitalizedDoc.getFamilyLabel().isCrfLabel()) {
+                String familyText = beHospitalizedDoc.getFamilyLabel().getText();
+                putContent(crfContent, medicalTextType.get(1), familyText, Content.family);
+            }
+            /* 辅助检查 */
+            if (beHospitalizedDoc.getPacsLabel() != null && beHospitalizedDoc.getPacsLabel().isCrfLabel()) {
+                String pacsText = beHospitalizedDoc.getPacsLabel().getText();
+                putContent(crfContent, medicalTextType.get(3), pacsText, Content.pacs + "含时间地点");
+                putContent(crfContent, medicalTextType.get(8), pacsText, Content.pacs);
+            }
+            /* 专科检查(专科体格检查) */
+            if (beHospitalizedDoc.getVitalLabelSpecial() != null && beHospitalizedDoc.getVitalLabelSpecial().isCrfLabel()) {
+                String vitalSpecialText = beHospitalizedDoc.getVitalLabelSpecial().getText();
+                putContent(crfContent, medicalTextType.get(7), vitalSpecialText, Content.special_exam);
+            }
+            /* 一般体格检查(存放一般查体) */
+            if (beHospitalizedDoc.getVitalLabel() != null && beHospitalizedDoc.getVitalLabel().isCrfLabel()) {
+                String vitalText = beHospitalizedDoc.getVitalLabel().getText();
+                putContent(crfContent, medicalTextType.get(4), vitalText, Content.phys_exam);
+            }
+            /* 初步诊断 */
+            if (beHospitalizedDoc.getInitialDiagLabel() != null && beHospitalizedDoc.getInitialDiagLabel().isCrfLabel()) {
+                String initialDiagText = beHospitalizedDoc.getInitialDiagLabel().getText();
+                if (StringUtil.isNotBlank(initialDiagText)) {
+                    /*initial_diag_text = CatalogueUtil.removeBetweenWordSpace(initial_diag_text);*/
+                    putContent(crfContent, medicalTextType.get(6), initialDiagText, Content.initial_diag);
+                }
+            }
+            /* 修正诊断 */
+            if (beHospitalizedDoc.getRevisedDiagLabel() != null && beHospitalizedDoc.getRevisedDiagLabel().isCrfLabel()) {
+                String revisedDiagText = beHospitalizedDoc.getRevisedDiagLabel().getText();
+                /*if (CatalogueUtil.numberExist(initial_diag_text)) {
+                    revised_diag_text = CatalogueUtil.removeBetweenWordSpace(revised_diag_text);
+                }*/
+                putContent(crfContent, medicalTextType.get(6), revisedDiagText, Content.revised_diag);
+            }
+            /* 补充诊断 */
+            if (beHospitalizedDoc.getSuppleDiagLabel() != null && beHospitalizedDoc.getSuppleDiagLabel().isCrfLabel()) {
+                String suppleDiagText = beHospitalizedDoc.getSuppleDiagLabel().getText();
+                /*if (CatalogueUtil.numberExist(initial_diag_text)) {
+                    supple_diag_text = CatalogueUtil.removeBetweenWordSpace(supple_diag_text);
+                }*/
+                putContent(crfContent, medicalTextType.get(6), suppleDiagText, Content.supple_diag);
+            }
+
+            JSONObject midData = loadAI(inputInfo.isUseCrfCache(), inputInfo.getMedicalRecordInfoDoc().getStructureMap().get("behospitalCode"), crfContent, crfServiceClient);
+
+            /* 处理主诉 */
+            if (beHospitalizedDoc.getChiefLabel() != null && beHospitalizedDoc.getChiefLabel().isCrfLabel()) {
+                putChiefCrfData(midData.getJSONObject(Content.chief), inputInfo);
+            }
+            /* 处理现病史 */
+            if (beHospitalizedDoc.getPresentLabel() != null && beHospitalizedDoc.getPresentLabel().isCrfLabel()) {
+                putPresentCrfData(midData.getJSONObject(Content.present), inputInfo);
+                beHospitalizedDoc.getPresentLabel().setCrfOutput(midData.getJSONObject(Content.present));
+                System.out.println(FastJsonUtils.getBeanToJson(beHospitalizedDoc.getPresentLabel()));
+            }
+            /* 处理既往史 */
+            if (beHospitalizedDoc.getPastLabel() != null && beHospitalizedDoc.getPastLabel().isCrfLabel()) {
+                putPastCrfData(midData.getJSONObject(Content.past), inputInfo);
+            }
+            /* 处理个人史 */
+            if (beHospitalizedDoc.getPersonalLabel() != null && beHospitalizedDoc.getPersonalLabel().isCrfLabel()) {
+                putPersonalCrfData(midData.getJSONObject(Content.personal), inputInfo);
+            }
+            /* 处理月经史 */
+            if (beHospitalizedDoc.getMenstrualLabel() != null && beHospitalizedDoc.getMenstrualLabel().isCrfLabel()) {
+                putMensesCrfData(midData.getJSONObject(Content.menses), inputInfo);
+            }
+            /* 处理家族史 */
+            if (beHospitalizedDoc.getFamilyLabel() != null && beHospitalizedDoc.getFamilyLabel().isCrfLabel()) {
+                putFamilyCrfData(midData.getJSONObject(Content.family), inputInfo);
+            }
+            /* 处理婚育史 */
+            if (beHospitalizedDoc.getMaritalLabel() != null && beHospitalizedDoc.getMaritalLabel().isCrfLabel()) {
+                putMaritalCrfData(midData.getJSONObject(Content.marriage), inputInfo);
+            }
+            /* 处理初步诊断 */
+            if (beHospitalizedDoc.getInitialDiagLabel() != null && beHospitalizedDoc.getInitialDiagLabel().isCrfLabel()) {
+                putInitialDiagCrfData(midData.getJSONObject(Content.initial_diag), inputInfo);
+            }
+            /* 处理修正诊断 */
+            if (beHospitalizedDoc.getRevisedDiagLabel() != null && beHospitalizedDoc.getRevisedDiagLabel().isCrfLabel()) {
+                putRevisedDiagCrfData(midData.getJSONObject(Content.revised_diag), inputInfo);
+            }
+            /* 处理补充诊断 */
+            if (beHospitalizedDoc.getSuppleDiagLabel() != null && beHospitalizedDoc.getSuppleDiagLabel().isCrfLabel()) {
+                putSuppleDiagCrfData(midData.getJSONObject(Content.supple_diag), inputInfo);
+            }
+            /* 处理专科体格检查 */
+            if (beHospitalizedDoc.getVitalLabelSpecial() != null && beHospitalizedDoc.getVitalLabelSpecial().isCrfLabel()) {
+                beHospitalizedDoc.getVitalLabelSpecial().setCrfOutput(midData.getJSONObject(Content.special_exam));
+            }
+            /* 处理辅助检查 */
+            if (beHospitalizedDoc.getPacsLabel() != null && beHospitalizedDoc.getPacsLabel().isCrfLabel()) {
+                /* 辅检提取时间、地点和提取疾病分为两个模型 */
+                putPacsCrfData(midData.getJSONObject(Content.pacs + "含时间地点"), inputInfo);
+                putPacsCrfData(midData.getJSONObject(Content.pacs), inputInfo);
+            }
+        }
+    }
+
+    public void putChiefCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //使用现病史结构
+        EntityProcessClinic entityProcessClinic = new EntityProcessClinic();
+        PresentLabel presentLabel = entityProcessClinic.extractEntity(aiOut);
+
+        ChiefLabel chiefLabel = inputInfo.getBeHospitalizedDoc().getChiefLabel();
+        chiefLabel.setClinicals(presentLabel.getClinicals());
+        chiefLabel.setDiags(presentLabel.getDiags());
+        chiefLabel.setPds(presentLabel.getPds());
+        System.out.println(FastJsonUtils.getBeanToJson(chiefLabel));
+    }
+
+    public void putPresentCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //放置入inputinfo
+        EntityProcessClinic entityProcessClinic = new EntityProcessClinic();
+        PresentLabel presentLabel = entityProcessClinic.extractEntity(aiOut);
+        presentLabel.setText(inputInfo.getBeHospitalizedDoc().getPresentLabel().getText());
+        List<Lis> lis = loadLises(aiOut);
+        presentLabel.setLises(lis);
+        inputInfo.getBeHospitalizedDoc().setPresentLabel(presentLabel);
+    }
+
+    /**
+     * 家族史
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putFamilyCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //家族史信息处理
+        EntityProcessFamily entityProcess = new EntityProcessFamily();
+        FamilyLabel familyLabel = entityProcess.extractEntity(aiOut);
+        familyLabel.setText(inputInfo.getBeHospitalizedDoc().getFamilyLabel().getText());
+        inputInfo.getBeHospitalizedDoc().setFamilyLabel(familyLabel);
+    }
+
+    /**
+     * 婚育史
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putMaritalCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //家族史信息处理
+        EntityProcessMarital entityProcess = new EntityProcessMarital();
+        MaritalLabel maritalLabel = entityProcess.extractEntity(aiOut);
+        maritalLabel.setText(inputInfo.getBeHospitalizedDoc().getMaritalLabel().getText());
+        inputInfo.getBeHospitalizedDoc().setMaritalLabel(maritalLabel);
+    }
+
+    public void putPastCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //放置入inputinfo
+        EntityProcessPast entityProcessPast = new EntityProcessPast();
+        PastLabel pastLabel = entityProcessPast.extractEntity(aiOut);
+        pastLabel.setText(inputInfo.getBeHospitalizedDoc().getPastLabel().getText());
+        inputInfo.getBeHospitalizedDoc().setPastLabel(pastLabel);
+
+    }
+
+    /**
+     * 个人史信息提取
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putPersonalCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //个人史信息提取
+        EntityProcessPersonal entityProcessPersonal = new EntityProcessPersonal();
+        PersonalLabel personalLabel = entityProcessPersonal.extractEntity(aiOut);
+        personalLabel.setText(inputInfo.getBeHospitalizedDoc().getPersonalLabel().getText());
+        inputInfo.getBeHospitalizedDoc().setPersonalLabel(personalLabel);
+    }
+
+    /**
+     * 月经史信息提取
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putMensesCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null || jsonObject.getJSONObject(entityRelationObject) == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //月经史信息处理
+        EntityProcessMenses entityProcess = new EntityProcessMenses();
+        MenstrualLabel menstrualLabel = entityProcess.extractEntity(aiOut);
+        menstrualLabel.setText(inputInfo.getBeHospitalizedDoc().getMenstrualLabel().getText());
+        inputInfo.getBeHospitalizedDoc().setMenstrualLabel(menstrualLabel);
+    }
+
+    /**
+     * 初步诊断信息提取
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putInitialDiagCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //诊断信息
+        EntityProcessDiag entityProcessDiag = new EntityProcessDiag();
+        List<Diag> diags = entityProcessDiag.extractEntity(aiOut);
+
+        DiagLabel initialDiagLabel = new DiagLabel();
+        initialDiagLabel.setText(inputInfo.getBeHospitalizedDoc().getInitialDiagLabel().getText());
+        initialDiagLabel.setDiags(diags);
+        inputInfo.getBeHospitalizedDoc().setInitialDiagLabel(initialDiagLabel);
+
+        //        //因为关系抽取未标注完成,先用规则
+        //        String diagString = inputInfo.getBeHospitalizedDoc().getInitialDiagLabel().getText();
+        //        if (StringUtils.isNotEmpty(diagString)) {
+        //            String[] diagArray = diagString.split(",");
+        //            List<Diag> diags = new ArrayList<>();
+        //            for (String d : diagArray) {
+        //                Diag diag = DiagEnhancer.create(d);
+        //                diags.add(diag);
+        //            }
+        //            InitialDiagLabel initialDiagLabel = new InitialDiagLabel();
+        //            initialDiagLabel.setDiags(diags);
+        //        }
+    }
+
+    /**
+     * 修正诊断信息提取
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putRevisedDiagCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //诊断信息
+        EntityProcessDiag entityProcessDiag = new EntityProcessDiag();
+        List<Diag> diags = entityProcessDiag.extractEntity(aiOut);
+
+        DiagLabel revisedDiagLabel = new DiagLabel();
+        revisedDiagLabel.setText(inputInfo.getBeHospitalizedDoc().getRevisedDiagLabel().getText());
+        revisedDiagLabel.setDiags(diags);
+        inputInfo.getBeHospitalizedDoc().setRevisedDiagLabel(revisedDiagLabel);
+
+        //替换初步诊断中的第一个诊断信息
+       /* DiagLabel initialDiagLabel = inputInfo.getBeHospitalizedDoc().getInitialDiagLabel();
+        if (initialDiagLabel.getDiags().size() > 0 && diags.size() > 0) {
+            initialDiagLabel.getDiags().remove(0);
+            initialDiagLabel.getDiags().add(0, diags.get(0));
+        }*/
+    }
+
+    /**
+     * 补充诊断信息提取
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putSuppleDiagCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //诊断信息
+        EntityProcessDiag entityProcessDiag = new EntityProcessDiag();
+        List<Diag> diags = entityProcessDiag.extractEntity(aiOut);
+
+        DiagLabel suppleDiagLabel = new DiagLabel();
+        suppleDiagLabel.setText(inputInfo.getBeHospitalizedDoc().getSuppleDiagLabel().getText());
+        suppleDiagLabel.setDiags(diags);
+        inputInfo.getBeHospitalizedDoc().setSuppleDiagLabel(suppleDiagLabel);
+    }
+
+    /**
+     * 辅助检查信息抽取
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putPacsCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        if (jsonObject == null) {
+            return;
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(BeHospitalizedAI.outputs);
+        if (aiOut == null) {
+            return;
+        }
+        //放置入inputinfo
+        PacsLabel pacsLabel = inputInfo.getBeHospitalizedDoc().getPacsLabel();
+        if (pacsLabel.getPacses() == null) {
+            pacsLabel.setPacses(loadPacses(aiOut));
+        } else {
+            List<Pacs> pacses = pacsLabel.getPacses();
+            pacses.addAll(loadPacses(aiOut));
+            pacsLabel.setPacses(pacses);
+        }
+    }
+
+    /**
+     * 关系抽取疾病信息
+     *
+     * @param aiOut
+     * @return
+     */
+    public List<Diag> loadDiags(JSONObject aiOut) {
+        //诊断信息
+        EntityProcessDiag entityProcessDiag = new EntityProcessDiag();
+        List<Diag> diags = entityProcessDiag.extractEntity(aiOut);
+        return diags;
+    }
+
+    /**
+     * 关系抽取化验信息
+     *
+     * @param aiOut
+     * @return
+     */
+    public List<Lis> loadLises(JSONObject aiOut) {
+        //化验信息
+        EntityProcessLis entityProcessLis = new EntityProcessLis();
+        List<Lis> lises = entityProcessLis.extractEntity(aiOut);
+        return lises;
+    }
+
+    /**
+     * 关系抽取辅检信息
+     *
+     * @param aiOut
+     * @return
+     */
+    public List<Pacs> loadPacses(JSONObject aiOut) {
+        //辅检信息
+        EntityProcessPacs entityProcessLis = new EntityProcessPacs();
+        List<Pacs> pacses = entityProcessLis.extractEntity(aiOut);
+        return pacses;
+    }
+
+    /**
+     * 关系抽取体格检查
+     *
+     * @param aiOut
+     * @return
+     */
+    public List<Vital> loadvital(JSONObject aiOut) {
+        //一般情况描述信息
+        EntityProcessVital entityProcessVital = new EntityProcessVital();
+        List<Vital> vitals = entityProcessVital.extractEntity(aiOut);
+        return vitals;
+    }
+
+    /**
+     * 从个人史取最后30个字,拼接到月经史
+     *
+     * @param concatMenstrual
+     * @param personalText
+     * @return
+     */
+    private String getConcatMenstrual(String concatMenstrual, String personalText) {
+        if (personalText != null) {
+            if (personalText.length() > 30) {
+                concatMenstrual = personalText.substring(personalText.length() - 30);
+            } else {
+                concatMenstrual = personalText;
+            }
+        }
+        return concatMenstrual;
+    }
+}

+ 92 - 0
structure-center/src/main/java/com/lantone/structure/ai/ConsultationAI.java

@@ -0,0 +1,92 @@
+package com.lantone.structure.ai;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.lantone.structure.client.CRFServiceClient;
+import com.lantone.structure.ai.process.EntityProcessDrug;
+import com.lantone.common.util.CatalogueUtil;
+import com.lantone.structure.model.InputInfo;
+import com.lantone.structure.model.doc.consultation.ConsultationDoc;
+import com.lantone.structure.model.doc.consultation.ConsultationResultsDoc;
+import com.lantone.structure.model.entity.Drug;
+import com.lantone.structure.model.label.ConsultationResultLabel;
+import com.lantone.common.util.StringUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : ConsultationAI
+ * @Description :
+ * @Author : 胡敬
+ * @Date: 2020-09-01 16:40
+ */
+public class ConsultationAI extends ModelAI {
+    /**
+     *
+     */
+    public static List<String> medicalTextType = Arrays.asList("CourseRecordSRR");
+    public static String entityRelationObject = "entity_relation_object";
+    public static String outputs = "outputs";
+    public static String content = "content";
+    public static List<String> mapKey = Lists.newArrayList("会诊意见", "病程内容");
+
+    public void medrec(InputInfo inputInfo, CRFServiceClient crfServiceClient) {
+        JSONArray crfContent = new JSONArray();
+        List<ConsultationDoc> docs = inputInfo.getConsultationDocs();
+        List<ConsultationResultsDoc> resultsDocs = docs.stream().map(ConsultationDoc::getConsultationResultsDoc).filter(Objects::nonNull).collect(Collectors.toList());
+        for (int i = 0; i < resultsDocs.size(); i++) {
+            Map<String, String> structureMap = resultsDocs.get(i).getStructureMap();
+            //存放抓取的药品
+            String content = CatalogueUtil.structureMapJoin(structureMap, mapKey);
+            putContent(crfContent, medicalTextType.get(0), content, i + "药物");
+        }
+
+        JSONObject midData = loadAI(inputInfo.isUseCrfCache(), inputInfo.getMedicalRecordInfoDoc().getStructureMap().get("behospitalCode"), crfContent, crfServiceClient);//crf返回数据
+
+        for (int i = 0; i < resultsDocs.size(); i++) {
+            if (midData.get(i + "药物") == null) {
+                continue;
+            }
+            ConsultationResultsDoc resultsDoc = resultsDocs.get(i);
+            ConsultationResultLabel consultationResultLabel = new ConsultationResultLabel();
+            List<Drug> drugs = putDrugCrfData(midData.getJSONObject(i + "药物"));
+            consultationResultLabel.setDrugs(drugs);
+            resultsDoc.setConsultationResultLabel(consultationResultLabel);
+        }
+    }
+
+
+    /**
+     * 存放抓取的药品
+     *
+     * @param jsonObject
+     */
+    public List<Drug> putDrugCrfData(JSONObject jsonObject) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return new ArrayList<>();
+        }
+        EntityProcessDrug entityProcessDrug = new EntityProcessDrug();
+        List<Drug> drugs = entityProcessDrug.extractEntity(aiOut);
+        return drugs;
+    }
+
+    protected void putContent(JSONArray crfContent, String medicalTextType, String text, String sign) {
+        String move_text = CatalogueUtil.removeSpecialChar(text);
+        if (StringUtil.isEmpty(move_text)) {
+            return;
+        }
+        JSONObject detailContent = new JSONObject();
+        detailContent.put("medical_text_type", medicalTextType);
+        detailContent.put("content", move_text);
+        detailContent.put("detail_title", sign);
+        detailContent.put("originalText", text);
+        crfContent.add(detailContent);
+    }
+}

+ 261 - 0
structure-center/src/main/java/com/lantone/structure/ai/FirstCourseRecordAI.java

@@ -0,0 +1,261 @@
+package com.lantone.structure.ai;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.lantone.structure.client.CRFServiceClient;
+import com.lantone.structure.client.SimilarityServiceClient;
+import com.lantone.structure.ai.process.EntityProcessClinic;
+import com.lantone.structure.ai.process.EntityProcessDiag;
+import com.lantone.structure.ai.process.EntityProcessDrug;
+import com.lantone.structure.ai.process.EntityProcessTreatPlan;
+import com.lantone.common.util.CatalogueUtil;
+import com.lantone.structure.model.Content;
+import com.lantone.structure.model.InputInfo;
+import com.lantone.structure.model.doc.FirstCourseRecordDoc;
+import com.lantone.structure.model.entity.Diag;
+import com.lantone.structure.model.entity.Drug;
+import com.lantone.structure.model.label.DrugLabel;
+import com.lantone.structure.model.label.PresentLabel;
+import com.lantone.structure.model.label.TreatPlanLabel;
+import com.lantone.common.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FirstCourseRecordAI
+ * @Description :
+ * @Author : 楼辉荣
+ * @Date: 2020-03-19 14:52
+ */
+public class FirstCourseRecordAI extends ModelAI {
+    /**
+     *
+     */
+    public static List<String> medicalTextType = Arrays.asList("FirstCoursera_cx", "Diagnoses_cx"
+            , "FirstCourseTreatment_cx", "CourseRecordSRR");
+    public static String entityRelationObject = "entity_relation_object";
+    public static String outputs = "outputs";
+    public static String content = "content";
+
+    public void medrec(InputInfo inputInfo, CRFServiceClient crfServiceClient, SimilarityServiceClient similarityServiceClient) {
+        JSONArray crfContent = new JSONArray();
+        JSONArray similarContent = new JSONArray();
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        if (firstCourseRecordDoc != null) {
+            Map<String, String> structureMap = firstCourseRecordDoc.getStructureMap();
+
+            //病历特点
+            //putContent(crfContent, medicalTextType.get(0), firstCourseRecordDoc.getCaseCharacteristicLabel().getText(), Content.case_feature);
+            //初步诊断
+            if (StringUtils.isNotEmpty(structureMap.get(Content.initial_diag))) {
+                String initial_diag = structureMap.get(Content.initial_diag);
+                /*if (CatalogueUtil.numberExist(initial_diag)) {
+                    initial_diag = CatalogueUtil.removeBetweenWordSpace(structureMap.get(Content.initial_diag));
+                }*/
+                putContent(crfContent, medicalTextType.get(1), initial_diag, Content.initial_diag);
+            } else if (firstCourseRecordDoc.getInitialDiagLabel() != null && StringUtil.isNotBlank(firstCourseRecordDoc.getInitialDiagLabel().getText())) {
+                String initial_diag = firstCourseRecordDoc.getInitialDiagLabel().getText();
+                /*if (CatalogueUtil.numberExist(initial_diag)) {
+                    initial_diag = CatalogueUtil.removeBetweenWordSpace(firstCourseRecordDoc.getInitialDiagLabel().getText());
+                }*/
+                putContent(crfContent, medicalTextType.get(1), initial_diag, Content.initial_diag);
+            }
+
+            //诊断依据
+            //putContent(crfContent, medicalTextType.get(0), firstCourseRecordDoc.getDiagnosisLabel().getText(), Content.diag_basis);
+            //鉴别诊断
+            if (StringUtils.isNotEmpty(structureMap.get("鉴别诊断"))) {
+                String diffDiag = structureMap.get("鉴别诊断");
+                /*if (CatalogueUtil.numberExist(diffDiag)) {
+                    diffDiag = CatalogueUtil.removeBetweenWordSpace(diffDiag);
+                }*/
+                putContent(crfContent, medicalTextType.get(1), diffDiag, "鉴别诊断");
+            } else if (firstCourseRecordDoc.getDifferentialDiagLabel() != null && StringUtil.isNotBlank(firstCourseRecordDoc.getDifferentialDiagLabel().getText())) {
+                String diffDiag = firstCourseRecordDoc.getDifferentialDiagLabel().getText();
+                /*if (CatalogueUtil.numberExist(diffDiag)) {
+                    diffDiag = CatalogueUtil.removeBetweenWordSpace(diffDiag);
+                }*/
+                putContent(crfContent, medicalTextType.get(1), diffDiag, "鉴别诊断");
+            }
+            //诊疗计划
+            TreatPlanLabel treatPlanLabel = firstCourseRecordDoc.getTreatPlanLabel();
+            if (treatPlanLabel != null && StringUtil.isNotBlank(treatPlanLabel.getAiText())) {
+                putContent(crfContent, medicalTextType.get(2), treatPlanLabel.getAiText(), "诊疗计划");
+            }
+
+            String drugContent = CatalogueUtil.structureMapJoin(structureMap, Lists.newArrayList("诊疗计划"));
+            putContent(crfContent, medicalTextType.get(3), drugContent, "药品");
+            /*
+            if (StringUtils.isNotEmpty(structureMap.get("诊疗计划")) && StringUtils.isNotEmpty(structureMap.get("需求评估"))) {
+                putContent(crfContent, medicalTextType.get(2), structureMap.get("诊疗计划") + structureMap.get("需求评估"), "诊疗计划");
+                firstCourseRecordDoc.getTreatPlanLabel().setText(structureMap.get("诊疗计划") + structureMap.get("需求评估"));
+            } else if (StringUtils.isNotEmpty(structureMap.get("诊疗计划"))) {
+                putContent(crfContent, medicalTextType.get(2), structureMap.get("诊疗计划"), "诊疗计划");
+                firstCourseRecordDoc.getTreatPlanLabel().setText(structureMap.get("诊疗计划"));
+            } else if (StringUtils.isNotEmpty(structureMap.get("需求评估"))) {
+                putContent(crfContent, medicalTextType.get(2), structureMap.get("需求评估"), "诊疗计划");
+                firstCourseRecordDoc.getTreatPlanLabel().setText(structureMap.get("需求评估"));
+            } else {
+                putContent(crfContent, medicalTextType.get(2), firstCourseRecordDoc.getTreatPlanLabel().getText(), "诊疗计划");
+            }
+             */
+
+            //病历特点与现病史比较相似度
+            if (inputInfo.getBeHospitalizedDoc() != null) {
+                //先从结构化数据找病例特点
+                if (StringUtil.isNotBlank(structureMap.get("现病史")) && inputInfo.getBeHospitalizedDoc().getPresentLabel() != null) {
+                    putContent(similarContent, structureMap.get("现病史"), inputInfo.getBeHospitalizedDoc().getPresentLabel().getText());
+                } else if (firstCourseRecordDoc.getCaseCharacteristicLabel() != null && StringUtil.isNotBlank(firstCourseRecordDoc.getCaseCharacteristicLabel().getText())
+                        && inputInfo.getBeHospitalizedDoc().getPresentLabel() != null) {
+                    //再从doc找病例特点
+                    putContent(similarContent, firstCourseRecordDoc.getCaseCharacteristicLabel().getText(), inputInfo.getBeHospitalizedDoc().getPresentLabel().getText());
+                }
+            }
+
+            JSONObject midData = loadAI(inputInfo.isUseCrfCache(), inputInfo.getMedicalRecordInfoDoc().getStructureMap().get("behospitalCode"), crfContent, crfServiceClient);//crf返回数据
+            //if (midData.containsKey(Content.case_feature)) {
+            //  putCaseCharacteristicCrfData(midData.getJSONObject(Content.case_feature), inputInfo);//处理病历特点
+            //}
+            if (midData.containsKey(Content.initial_diag)) {
+                putInitialDiagCrfData(midData.getJSONObject(Content.initial_diag), inputInfo);//处理初步诊断
+            }
+            //if (midData.containsKey(Content.diag_basis)) {
+            //    putDiagnosisCrfData(midData.getJSONObject(Content.diag_basis), inputInfo);//处理诊断依据
+            //}
+            if (midData.containsKey("鉴别诊断")) {
+                putDifferentialDiagCrfData(midData.getJSONObject("鉴别诊断"), inputInfo);//处理鉴别诊断
+            }
+            if (midData.containsKey("诊疗计划")) {
+                putTreatPlanCrfData(midData.getJSONObject("诊疗计划"), inputInfo);//处理诊疗计划
+            }
+            if (midData.containsKey("药品")) {
+                putDrugCrfData(midData.getJSONObject("药品"), inputInfo);
+            }
+
+            double likeRate = loadSimilarAI(similarContent, similarityServiceClient);
+            putCaseCharacteristicSimilarData(likeRate, inputInfo);//存放与现病史文本相似度
+        }
+    }
+
+    /**
+     * 病历特点
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putCaseCharacteristicCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        //使用现病史结构来处理病历特点
+        if (aiOut == null) {
+            return;
+        }
+        EntityProcessClinic entityProcessClinic = new EntityProcessClinic();
+        PresentLabel presentLabel = entityProcessClinic.extractEntity(aiOut);
+        //临床表现
+        inputInfo.getFirstCourseRecordDoc().getCaseCharacteristicLabel().setClinicals(presentLabel.getClinicals());
+    }
+
+    /**
+     * 病历特点与现病史相似度
+     *
+     * @param likeRate
+     * @param inputInfo
+     */
+    public void putCaseCharacteristicSimilarData(double likeRate, InputInfo inputInfo) {
+        //存放与现病史文本相似度
+        inputInfo.getFirstCourseRecordDoc().getCaseCharacteristicLabel().setLikeRate(likeRate);
+    }
+
+    /**
+     * 初步诊断
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putInitialDiagCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        //诊断信息
+        EntityProcessDiag entityProcessDiag = new EntityProcessDiag();
+        List<Diag> diags = entityProcessDiag.extractEntity(aiOut);
+        inputInfo.getFirstCourseRecordDoc().getInitialDiagLabel().setDiags(diags);
+    }
+
+    /**
+     * 诊断依据
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putDiagnosisCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        //使用现病史结构来处理诊断依据
+        EntityProcessClinic entityProcessClinic = new EntityProcessClinic();
+        PresentLabel presentLabel = entityProcessClinic.extractEntity(aiOut);
+        //临床表现
+        inputInfo.getFirstCourseRecordDoc().getDiagnosisLabel().setClinicals(presentLabel.getClinicals());
+    }
+
+    /**
+     * 鉴别诊断
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putDifferentialDiagCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        //诊断信息
+        EntityProcessDiag entityProcessDiag = new EntityProcessDiag();
+        List<Diag> diags = entityProcessDiag.extractEntity(aiOut);
+        inputInfo.getFirstCourseRecordDoc().getDifferentialDiagLabel().setDiags(diags);
+    }
+
+    /**
+     * 诊疗计划
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putTreatPlanCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        //诊疗计划
+        EntityProcessTreatPlan entityProcessTreatPlan = new EntityProcessTreatPlan();
+        TreatPlanLabel treatPlanLabel = entityProcessTreatPlan.extractEntity(aiOut);
+        treatPlanLabel.setText(inputInfo.getFirstCourseRecordDoc().getTreatPlanLabel().getText());
+        inputInfo.getFirstCourseRecordDoc().setTreatPlanLabel(treatPlanLabel);
+    }
+
+    /**
+     * 存放抓取的药品
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putDrugCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        EntityProcessDrug entityProcessDrug = new EntityProcessDrug();
+        List<Drug> drugs = entityProcessDrug.extractEntity(aiOut);
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        DrugLabel label = new DrugLabel();
+        label.setDrugs(drugs);
+        firstCourseRecordDoc.setDrugLabel(label);
+    }
+}

+ 152 - 0
structure-center/src/main/java/com/lantone/structure/ai/LeaveHospitalAI.java

@@ -0,0 +1,152 @@
+package com.lantone.structure.ai;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.lantone.structure.client.CRFServiceClient;
+import com.lantone.structure.ai.process.EntityProcessDiag;
+import com.lantone.structure.ai.process.EntityProcessDrug;
+import com.lantone.structure.ai.process.EntityProcessLeaveHospital;
+import com.lantone.common.util.CatalogueUtil;
+import com.lantone.structure.model.Content;
+import com.lantone.structure.model.InputInfo;
+import com.lantone.structure.model.doc.LeaveHospitalDoc;
+import com.lantone.structure.model.entity.Diag;
+import com.lantone.structure.model.entity.Drug;
+import com.lantone.structure.model.label.DiagLabel;
+import com.lantone.structure.model.label.LeaveHospitalLabel;
+import com.lantone.common.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : DischargeAI
+ * @Description :
+ * @Author : 胡敬
+ * @Date: 2020-03-20 11:00
+ */
+public class LeaveHospitalAI extends ModelAI {
+    /**
+     *
+     */
+    public static List<String> medicalTextType = Arrays.asList("DischargeQA_cx", "Diagnoses_cx", "CourseRecordSRR");
+    public static String entityRelationObject = "entity_relation_object";
+    public static String outputs = "outputs";
+    public static String content = "content";
+
+    public void medrec(InputInfo inputInfo, CRFServiceClient crfServiceClient) {
+        JSONArray crfContent = new JSONArray();
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        if (leaveHospitalDoc != null) {
+            if (StringUtils.isNotEmpty(leaveHospitalDoc.getText())) {
+                //出院小结全部文本(之后考虑删除传全部文本,改为传相应结构化文本)
+                putContent(crfContent, medicalTextType.get(0), leaveHospitalDoc.getText(), Content.discharge);
+            }
+
+            Map<String, String> leaveHospitalStructureMap = leaveHospitalDoc.getStructureMap();
+            //入院情况
+            //if (leaveHospitalStructureMap.get(Content.inStatus) != null) {
+            //    putContent(crfContent, medicalTextType.get(1), leaveHospitalStructureMap.get(Content.inStatus), Content.inStatus);
+            //}
+            //出院诊断
+            if (StringUtil.isNotBlank(leaveHospitalStructureMap.get(Content.dischargeDiag))) {
+                String dischargeDiag = leaveHospitalStructureMap.get(Content.dischargeDiag);
+                    /*if (CatalogueUtil.numberExist(dischargeDiag)) {
+                        dischargeDiag = CatalogueUtil.removeBetweenWordSpace(dischargeDiag);
+                    }*/
+                putContent(crfContent, medicalTextType.get(1), dischargeDiag, Content.dischargeDiag);
+            }
+            if (leaveHospitalDoc.getLeaveHospitalDoctorAdviceLabel() != null
+                    && StringUtils.isNotEmpty(leaveHospitalDoc.getLeaveHospitalDoctorAdviceLabel().getAiText())) {
+                putContent(crfContent, medicalTextType.get(0), leaveHospitalDoc.getLeaveHospitalDoctorAdviceLabel().getAiText(), Content.leaveHospitalDoctorAdvice);
+            }
+            //药品
+            String drugContent = CatalogueUtil.structureMapJoin(leaveHospitalStructureMap, Lists.newArrayList("诊治经过", "出院带药"));
+            putContent(crfContent, medicalTextType.get(2), drugContent, "药品");
+
+            JSONObject midData = loadAI(inputInfo.isUseCrfCache(), inputInfo.getMedicalRecordInfoDoc().getStructureMap().get("behospitalCode"), crfContent, crfServiceClient);//crf返回数据
+            if (midData.containsKey(Content.discharge)) {
+                putDischargeCrfData(midData.getJSONObject(Content.discharge), inputInfo);//出院小结
+            }
+            if (midData.containsKey(Content.dischargeDiag)) {
+                putDiagCrfData(midData.getJSONObject(Content.dischargeDiag), inputInfo);//出院诊断
+            }
+            if (midData.containsKey(Content.leaveHospitalDoctorAdvice)) {
+                //putLeaveHospitalDoctorAdviceCrfData(midData.getJSONObject(Content.leaveHospitalDoctorAdvice), inputInfo);//出院医嘱
+            }
+            if (midData.containsKey("药品")) {
+                putDrugCrfData(midData.getJSONObject("药品"), inputInfo);
+            }
+        }
+    }
+
+
+    /**
+     * 病历特点
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putDischargeCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        EntityProcessLeaveHospital entityProcessLeaveHospital = new EntityProcessLeaveHospital();
+        LeaveHospitalLabel leaveHospitalLabel = entityProcessLeaveHospital.extractEntity(aiOut);
+        inputInfo.getLeaveHospitalDoc().setLeaveHospitalLabel(leaveHospitalLabel);
+    }
+
+    /**
+     * 存放抓取的疾病
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putDiagCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        EntityProcessDiag entityProcessDiag = new EntityProcessDiag();
+        List<Diag> diags = entityProcessDiag.extractEntity(aiOut);
+        DiagLabel diagLabel = new DiagLabel();
+        diagLabel.setDiags(diags);
+        inputInfo.getLeaveHospitalDoc().setLeaveDiagLabel(diagLabel);
+    }
+
+    /**
+     * 存放抓取的药品
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putDrugCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        EntityProcessDrug entityProcessDrug = new EntityProcessDrug();
+        List<Drug> drugs = entityProcessDrug.extractEntity(aiOut);
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        if (leaveHospitalDoc.getLeaveHospitalLabel() == null) {
+            LeaveHospitalLabel label = new LeaveHospitalLabel();
+            label.setDrugs(drugs);
+            leaveHospitalDoc.setLeaveHospitalLabel(label);
+        } else {
+            leaveHospitalDoc.getLeaveHospitalLabel().setDrugs(drugs);
+        }
+    }
+
+    /**
+     * 出院医嘱
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putLeaveHospitalDoctorAdviceCrfData(JSONObject jsonObject, InputInfo inputInfo) {
+    }
+}

+ 247 - 0
structure-center/src/main/java/com/lantone/structure/ai/ModelAI.java

@@ -0,0 +1,247 @@
+package com.lantone.structure.ai;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.client.CRFServiceClient;
+import com.lantone.structure.client.ChiefPresentSimilarityServiceClient;
+import com.lantone.structure.client.SimilarityServiceClient;
+import com.lantone.common.util.CatalogueUtil;
+import com.lantone.structure.model.entity.Annotation;
+import com.lantone.structure.model.entity.ChiefPresentAnnotation;
+import com.lantone.structure.model.vo.CRFVo;
+import com.lantone.structure.model.vo.ChiefPresentSimilarityVo;
+import com.lantone.structure.model.vo.SimilarityVo;
+import com.lantone.common.util.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+/**
+ * @ClassName : ModelAI
+ * @Description : 算法基类
+ * @Author : 楼辉荣
+ * @Date: 2020-03-19 15:08
+ */
+@Slf4j
+public class ModelAI {
+    /**
+     * 获取CRF返回数据
+     *
+     * @param crfContent
+     * @param crfServiceClient
+     * @return
+     */
+    protected JSONObject loadAI(boolean useCrfCache, String behospitalCode, JSONArray crfContent, CRFServiceClient crfServiceClient) {
+        JSONArray data = null;
+        String classname = this.getClass().getName();
+        if (data == null) {
+            //存储CRF完整所需结构数据
+            CRFVo crfVo = new CRFVo();
+            crfVo.setData(crfContent);
+            long t1 = System.currentTimeMillis();
+            //获取CRF模型返回数据
+            data = getAnnotation(crfServiceClient, crfVo).getData();
+            long t2 = System.currentTimeMillis();
+            log.error(behospitalCode + "-----" + classname + "(CRF)  耗时:" + (t2 - t1));
+        }
+        JSONObject midData = getOutputs(data);
+        return midData;
+    }
+
+    protected JSONObject loadEntity(JSONObject jsonObject, String entityRelationObject, String outputs, String content) {
+        if (jsonObject == null) {
+            return new JSONObject();
+        }
+        JSONObject aiOut = jsonObject.getJSONObject(entityRelationObject).getJSONObject(outputs);
+        aiOut.put(content, jsonObject.getJSONObject(entityRelationObject).getString(content));
+        return aiOut;
+    }
+
+    private Annotation getAnnotation(CRFServiceClient crfServiceClient, CRFVo crfVo) {
+        Annotation annotation = new Annotation();
+        try {
+            String annotation_str = crfServiceClient.getAnnotation(crfVo);
+            annotation = JSON.parseObject(annotation_str, Annotation.class);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        } finally {
+            return annotation;
+        }
+    }
+
+    protected void putContent(JSONArray crfContent, String medicalTextType, String text, String sign) {
+        String move_text = CatalogueUtil.removeSpecialChar(text);
+        if (StringUtil.isEmpty(move_text)) {
+            return;
+        }
+        JSONObject detailContent = new JSONObject();
+        detailContent.put("medical_text_type", medicalTextType);
+        detailContent.put("content", move_text);
+        detailContent.put("detail_title", sign);
+        crfContent.add(detailContent);
+    }
+
+    protected void putContent(JSONArray crfContent, String medicalTextType, String firstText, String secondText, String sign) {
+        String firstMoveText = CatalogueUtil.removeSpecialChar(firstText);
+        String secondMoveText = CatalogueUtil.removeSpecialChar(secondText);
+        if (StringUtil.isEmpty(firstMoveText) && StringUtil.isEmpty(secondMoveText)) {
+            return;
+        }
+        JSONObject detailContent = new JSONObject();
+        detailContent.put("medical_text_type", medicalTextType);
+        detailContent.put("content", firstMoveText + "\n" + secondMoveText);
+        detailContent.put("detail_title", sign);
+        crfContent.add(detailContent);
+    }
+
+    /**
+     * 获取CRF模型输出并处理
+     *
+     * @param data
+     * @return
+     */
+    public JSONObject getOutputs(JSONArray data) {
+        JSONObject midData = new JSONObject();
+        for (int i = 0; i < data.size(); i++) {
+            JSONObject detailContent = data.getJSONObject(i);
+            String detail_title = detailContent.getString("detail_title");
+            if (StringUtil.isNotEmpty(detail_title) && midData.get(detail_title) == null) {
+                midData.put(detail_title, detailContent);
+            }
+        }
+        return midData;
+    }
+
+    /*****************************文本相似度算法************************************/
+
+    /**
+     * 存放文本相似度入参内容
+     *
+     * @param similarContent
+     * @param firstText
+     * @param secondText
+     */
+    public void putContent(JSONArray similarContent, String firstText, String secondText) {
+        String moveFirstText = CatalogueUtil.removeSpecialChar(firstText);
+        String moveSecondText = CatalogueUtil.removeSpecialChar(secondText);
+        if (StringUtil.isEmpty(moveFirstText) || StringUtil.isEmpty(moveSecondText)) {
+            return;
+        }
+        JSONObject detailContent = new JSONObject();
+        detailContent.put("text_1", moveFirstText);
+        detailContent.put("text_2", moveSecondText);
+        similarContent.add(detailContent);
+    }
+
+    private Annotation getAnnotation(SimilarityServiceClient similarityServiceClient, SimilarityVo similarityVo) {
+        Annotation annotation = new Annotation();
+        try {
+            String annotation_str = similarityServiceClient.getAnnotation(similarityVo);
+            annotation = JSON.parseObject(annotation_str, Annotation.class);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        } finally {
+            return annotation;
+        }
+    }
+
+    /**
+     * 获取文本相似度返回数据
+     *
+     * @param similarContent
+     * @param similarityServiceClient
+     * @return
+     */
+    public double loadSimilarAI(JSONArray similarContent, SimilarityServiceClient similarityServiceClient) {
+        //存储CRF完整所需结构数据
+        SimilarityVo similarityVo = new SimilarityVo();
+        similarityVo.setData(similarContent);
+        //获取CRF模型返回数据
+        JSONArray data = getAnnotation(similarityServiceClient, similarityVo).getData();
+        return getSimilarOutputs(data);
+    }
+
+    /**
+     * 获取文本相似度模型输出并处理
+     *
+     * @param data 数组里只有一个对象
+     * @return
+     */
+    public double getSimilarOutputs(JSONArray data) {
+        double likeRate = 0d;
+        if (data.size() > 0) {
+            JSONObject dataContent = data.getJSONObject(0);
+            likeRate = dataContent.getDoubleValue("like_rate");
+        }
+        return likeRate;
+    }
+    /*****************************主诉现病史症状文本相似度算法************************************/
+
+    /**
+     * 存放主诉现病史症状文本相似度入参内容
+     */
+    public void putContent(JSONObject similarContent, String firstText, List<String> clinicArr) {
+        if (StringUtil.isEmpty(firstText) || clinicArr.size() == 0) {
+            return;
+        }
+        similarContent.put("string1", firstText);
+        similarContent.put("string2", clinicArr);
+    }
+
+    /**
+     * 获取主诉现病史症状相似度返回数据
+     *
+     * @param string1
+     * @param string2
+     * @param chiefPresentSimilarityServiceClient
+     * @return
+     */
+    public JSONArray loadChiefPresentSimilarAI(String string1, List<String> string2, boolean directionCheck
+            , String modelName, ChiefPresentSimilarityServiceClient chiefPresentSimilarityServiceClient) {
+        //存储CRF完整所需结构数据
+        ChiefPresentSimilarityVo similarityVo = new ChiefPresentSimilarityVo();
+        JSONObject data = new JSONObject();
+        putContent(data, string1, string2);
+        similarityVo.setData(data);
+        similarityVo.setDirection_check(directionCheck);
+        similarityVo.setModel_name(modelName);
+        //获取CRF模型返回数据
+        JSONArray predY = getAnnotation(chiefPresentSimilarityServiceClient, similarityVo).getPred_y();
+        return getChiefPresentSimilarOutputs(predY);
+    }
+
+    /**
+     * 主诉现病史相似度接口返回
+     *
+     * @param chiefPresentSimilarityServiceClient
+     * @param chiefPresentSimilarityVo
+     * @return
+     */
+    private ChiefPresentAnnotation getAnnotation(ChiefPresentSimilarityServiceClient chiefPresentSimilarityServiceClient,
+                                                 ChiefPresentSimilarityVo chiefPresentSimilarityVo) {
+        ChiefPresentAnnotation annotation = new ChiefPresentAnnotation();
+        try {
+            String annotation_str = chiefPresentSimilarityServiceClient.getAnnotation(chiefPresentSimilarityVo);
+            annotation = JSON.parseObject(annotation_str, ChiefPresentAnnotation.class);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        } finally {
+            return annotation;
+        }
+    }
+
+    /**
+     * 获取主诉现病史文本相似度模型输出并处理
+     *
+     * @param predY
+     * @return
+     */
+    public JSONArray getChiefPresentSimilarOutputs(JSONArray predY) {
+        JSONArray dataArr = new JSONArray();
+        if (predY != null && predY.size() > 0) {
+            dataArr = predY.getJSONArray(0);
+        }
+        return dataArr;
+    }
+}

+ 133 - 0
structure-center/src/main/java/com/lantone/structure/ai/OperationAI.java

@@ -0,0 +1,133 @@
+package com.lantone.structure.ai;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.lantone.structure.client.CRFServiceClient;
+import com.lantone.structure.ai.process.EntityProcessDrug;
+import com.lantone.structure.ai.process.EntityProcessOperationDiscussion;
+import com.lantone.common.util.CatalogueUtil;
+import com.lantone.structure.model.Content;
+import com.lantone.structure.model.InputInfo;
+import com.lantone.structure.model.doc.operation.OperationDiscussionDoc;
+import com.lantone.structure.model.doc.operation.OperationDoc;
+import com.lantone.structure.model.doc.operation.OperationRecordDoc;
+import com.lantone.structure.model.entity.Drug;
+import com.lantone.structure.model.label.OperationDiscussionLabel;
+import com.lantone.structure.model.label.OperationRecordLabel;
+import com.lantone.common.util.StringUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : OperationAI
+ * @Description :
+ * @Author : 胡敬
+ * @Date: 2020-03-24 09:52
+ */
+public class OperationAI extends ModelAI {
+    /**
+     *
+     */
+    public static List<String> medicalTextType = Arrays.asList("CourseAfterOperation_cx", "CourseRecordSRR");
+    public static String entityRelationObject = "entity_relation_object";
+    public static String outputs = "outputs";
+    public static String content = "content";
+    public static List<String> discussionKey = Lists.newArrayList("术前诊断", "术中后诊断", "手术名称", "麻醉方式"
+            , "手术简要经过", "目前情况", "术后注意事项");
+
+    public void medrec(InputInfo inputInfo, CRFServiceClient crfServiceClient) {
+        JSONArray crfContent = new JSONArray();
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        for (int i = 0; i < operationDocs.size(); i++) {
+            if (operationDocs.get(i).getOperationRecordDoc() != null) {
+                OperationRecordDoc operationRecordDoc = operationDocs.get(i).getOperationRecordDoc();
+                Map<String, String> structureMap = operationRecordDoc.getStructureMap();
+                //存放抓取的药品
+                String content = CatalogueUtil.structureMapJoin(structureMap, Lists.newArrayList("手术经过及处理", "手术中用药(化疗等药物)"));
+                putContent(crfContent, medicalTextType.get(1), content, "手术记录" + i + "药物");
+            }
+            if (operationDocs.get(i).getOperationDiscussionDoc() != null) {
+                OperationDiscussionDoc operationDiscussionDoc = operationDocs.get(i).getOperationDiscussionDoc();
+                Map<String, String> structureMap = operationDiscussionDoc.getStructureMap();
+                String discussionText = CatalogueUtil.structureMapJoin(structureMap, discussionKey);
+                putContent(crfContent, medicalTextType.get(0), discussionText, Content.operation_Discussion + i);
+                //存放抓取的药品
+                String content = CatalogueUtil.structureMapJoin(structureMap, Lists.newArrayList("治疗计划和措施", "术后处理措施"));
+                putContent(crfContent, medicalTextType.get(1), content, Content.operation_Discussion + i + "药物");
+            }
+        }
+
+        JSONObject midData = loadAI(inputInfo.isUseCrfCache(), inputInfo.getMedicalRecordInfoDoc().getStructureMap().get("behospitalCode"), crfContent, crfServiceClient);//crf返回数据
+
+        for (int i = 0; i < operationDocs.size(); i++) {
+            if (midData.get("手术记录" + i + "药物") != null) {
+                OperationRecordDoc operationRecordDoc = operationDocs.get(i).getOperationRecordDoc();
+                //手术记录药品
+                OperationRecordLabel operationRecordLabel = new OperationRecordLabel();
+                operationRecordLabel.setDrugs(putDrugCrfData(midData.getJSONObject("手术记录" + i + "药物")));
+            }
+            if (midData.get(Content.operation_Discussion + i) != null) {
+                OperationDiscussionDoc discussionDoc = operationDocs.get(i).getOperationDiscussionDoc();
+                OperationDiscussionLabel discussionLabel = putOperationDiscussionCrfData(midData.getJSONObject(Content.operation_Discussion + i));
+                if (discussionLabel != null) {
+                    discussionDoc.setOperationDiscussionLabel(discussionLabel);
+                }
+                //术后首程药品
+                if (midData.get(Content.operation_Discussion + i + "药物") != null) {
+                    discussionLabel = operationDocs.get(i).getOperationDiscussionDoc().getOperationDiscussionLabel();
+                    if (discussionLabel == null) {
+                        discussionLabel = new OperationDiscussionLabel();
+                    }
+                    discussionLabel.setDrugs(putDrugCrfData(midData.getJSONObject(Content.operation_Discussion + i + "药物")));
+                }
+            }
+        }
+    }
+
+    /**
+     * 处理手术记录
+     *
+     * @param jsonObject
+     */
+    public OperationDiscussionLabel putOperationDiscussionCrfData(JSONObject jsonObject) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return null;
+        }
+        String originalText = jsonObject.getString("originalText");
+        EntityProcessOperationDiscussion entityProcessOperationDiscussion = new EntityProcessOperationDiscussion();
+        return entityProcessOperationDiscussion.extractEntity(aiOut);
+    }
+
+    /**
+     * 存放抓取的药品
+     *
+     * @param jsonObject
+     */
+    public List<Drug> putDrugCrfData(JSONObject jsonObject) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return new ArrayList<>();
+        }
+        EntityProcessDrug entityProcessDrug = new EntityProcessDrug();
+        List<Drug> drugs = entityProcessDrug.extractEntity(aiOut);
+        return drugs;
+    }
+
+    protected void putContent(JSONArray crfContent, String medicalTextType, String text, String sign) {
+        String move_text = CatalogueUtil.removeSpecialChar(text);
+        if (StringUtil.isEmpty(move_text)) {
+            return;
+        }
+        JSONObject detailContent = new JSONObject();
+        detailContent.put("medical_text_type", medicalTextType);
+        detailContent.put("content", move_text);
+        detailContent.put("detail_title", sign);
+        detailContent.put("originalText", text);
+        crfContent.add(detailContent);
+    }
+}

+ 376 - 0
structure-center/src/main/java/com/lantone/structure/ai/ThreeLevelWardAI.java

@@ -0,0 +1,376 @@
+package com.lantone.structure.ai;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.lantone.structure.client.CRFServiceClient;
+import com.lantone.structure.ai.process.EntityProcessThreeLevelWard;
+import com.lantone.common.util.CatalogueUtil;
+import com.lantone.structure.model.Content;
+import com.lantone.structure.model.InputInfo;
+import com.lantone.structure.model.doc.DifficultCaseDiscussDoc;
+import com.lantone.structure.model.doc.RescueDoc;
+import com.lantone.structure.model.doc.ThreeLevelWardDoc;
+import com.lantone.structure.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.structure.model.doc.ward.DirectorDoctorWardDoc;
+import com.lantone.structure.model.label.ThreeLevelWardLabel;
+import com.lantone.common.util.ListUtil;
+import com.lantone.common.util.StringUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @ClassName : ThreeLevelWardAI
+ * @Description :
+ * @Author : 胡敬
+ * @Date: 2020-03-23 09:52
+ */
+public class ThreeLevelWardAI extends ModelAI {
+    /**
+     *
+     */
+    public static List<String> medicalTextType = Arrays.asList("CourseRecord_cx", "CourseRecordLast_cx", "CourseRecordSRR");
+    public static String entityRelationObject = "entity_relation_object";
+    public static String outputs = "outputs";
+    public static String content = "content";
+
+    public void medrec(InputInfo inputInfo, CRFServiceClient crfServiceClient) {
+        JSONArray crfContent = new JSONArray();
+        List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
+        if (threeLevelWardDocs.size() == 0) {
+            return;
+        }
+        ThreeLevelWardDoc threeLevelWardDoc = threeLevelWardDocs.get(0);
+        List<AttendingDoctorWardDoc> attendingDocs = threeLevelWardDoc.getAttendingDoctorWardDocs();//主治医师查房记录
+        if (attendingDocs.size() > 0) {
+            //主治医师首次查房记录
+            Map<String, String> fitstAttStructureMap = attendingDocs.get(0).getStructureMap();
+            putContent(crfContent, medicalTextType.get(0), fitstAttStructureMap.get("病情记录"), Content.attend);
+        }
+
+        List<DirectorDoctorWardDoc> directorDocs = threeLevelWardDoc.getDirectorDoctorWardDocs();//主任医师查房记录
+        if (directorDocs.size() > 0) {
+            //主任医师首次查房记录
+            Map<String, String> fitstDirStructureMap = directorDocs.get(0).getStructureMap();
+            putContent(crfContent, medicalTextType.get(0), fitstDirStructureMap.get("病情记录"), Content.director);
+
+            //主任医师最后一次查房记录
+            Map<String, String> lastDirStructureMap = directorDocs.get(directorDocs.size() - 1).getStructureMap();
+            putContent(crfContent, medicalTextType.get(0), lastDirStructureMap.get("病情记录"), Content.director + "最后一次");
+        }
+
+        //所有查房记录,2020/08/20新增所有查房记录抽取:实验室检查、辅助检查、药品等
+        List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+        if (allDoctorWradDocs.size() > 0) {
+            Map<String, String> lastWardStructureMap = allDoctorWradDocs.get(allDoctorWradDocs.size() - 1).getStructureMap();
+            putContent(crfContent, medicalTextType.get(1), lastWardStructureMap.get("病情记录"), "末次查房");
+            //2020/08/20新增所有查房记录抽取:实验室检查、辅助检查、药品等
+            for (int i = 0; i < allDoctorWradDocs.size(); i++) {
+                Map<String, String> structureMap = allDoctorWradDocs.get(i).getStructureMap();
+                String content = CatalogueUtil.structureMapJoin(structureMap, Lists.newArrayList("体检", "病情记录", "治疗计划和措施"));
+                putContent(crfContent, medicalTextType.get(2), content, "第" + i + "次查房");
+            }
+
+        }
+
+        List<Map<String, String>> directorDifficultRecord = new ArrayList<>();
+        //疑难患者副高及以上查房记录
+        if (inputInfo.getDifficultCaseDiscussDocs().size() > 0) {
+            directorDifficultRecord = putDirectorDifficultRecord(inputInfo, allDoctorWradDocs);
+            for (int i = 0; i < directorDifficultRecord.size(); i++) {
+                putContent(crfContent, medicalTextType.get(0), directorDifficultRecord.get(i).get("病情记录"), Content.difficultPatients + i, directorDifficultRecord.get(i).get("查房日期"));
+            }
+        }
+        List<Map<String, String>> directorRescueRecord = new ArrayList<>();
+        //抢救患者副高及以上查房记录
+        if (inputInfo.getRescueDocs().size() > 0) {
+            directorRescueRecord = putDirectorRescueRecord(inputInfo, allDoctorWradDocs);
+            for (int i = 0; i < directorRescueRecord.size(); i++) {
+                putContent(crfContent, medicalTextType.get(0), directorRescueRecord.get(i).get("病情记录"), Content.rescuingPatients + i, directorRescueRecord.get(i).get("查房日期"));
+            }
+        }
+
+        JSONObject midData = loadAI(inputInfo.isUseCrfCache(), inputInfo.getMedicalRecordInfoDoc().getStructureMap().get("behospitalCode"), crfContent, crfServiceClient);//crf返回数据
+
+        //主治医师首次查房记录模型输出
+        if (midData.get(Content.attend) != null) {
+            attendingDocs.get(0).setThreeLevelWardLabel(putWardRoundCrfData(midData.getJSONObject(Content.attend)));
+        }
+        //主任医师首次查房记录模型输出
+        if (midData.get(Content.director) != null) {
+            directorDocs.get(0).setThreeLevelWardLabel(putWardRoundCrfData(midData.getJSONObject(Content.director)));
+        }
+        //主任医师最后一次查房记录模型输出
+        if (midData.get(Content.director + "最后一次") != null) {
+            directorDocs.get(directorDocs.size() - 1).setThreeLevelWardLabel(putWardRoundCrfData(midData.getJSONObject(Content.director + "最后一次")));
+        }
+        //最后一次查房记录模型输出
+        if (midData.get("末次查房") != null) {
+            allDoctorWradDocs.get(allDoctorWradDocs.size() - 1).setThreeLevelWardLabel(Lists.newArrayList(putWardRoundCrfData(midData.getJSONObject("末次查房"))));
+        }
+        //疑难患者副高及以上查房记录模型输出
+        if (inputInfo.getDifficultCaseDiscussDocs().size() > 0 && ListUtil.isNotEmpty(directorDifficultRecord)) {
+            for (int i = 0; i < directorDifficultRecord.size(); i++) {
+                if (midData.get(Content.difficultPatients + i) == null) {
+                    continue;
+                }
+                putWardRoundCrfData(midData.getJSONObject(Content.difficultPatients + i), inputInfo, 2);//查房记录
+            }
+        }
+        //抢救患者副高及以上查房记录模型输出
+        if (inputInfo.getRescueDocs().size() > 0 && ListUtil.isNotEmpty(directorDifficultRecord)) {
+            for (int i = 0; i < directorDifficultRecord.size(); i++) {
+                if (midData.get(Content.rescuingPatients + i) == null) {
+                    continue;
+                }
+                putWardRoundCrfData(midData.getJSONObject(Content.rescuingPatients + i), inputInfo, 3);//查房记录
+            }
+        }
+
+        //2020/08/20新增所有查房记录抽取:实验室检查、辅助检查、药品等
+        for (int i = 0; i < allDoctorWradDocs.size(); i++) {
+            if (midData.get("第" + i + "次查房") == null) {
+                continue;
+            }
+            putWardRoundCrfData(midData.getJSONObject("第" + i + "次查房"), inputInfo, 0);//查房记录
+        }
+
+    }
+
+    protected void putContent(JSONArray crfContent, String medicalTextType, String text, String sign, String wardDate) {
+        String moveText = CatalogueUtil.removeSpecialChar(text);
+        if (StringUtil.isEmpty(moveText)) {
+            return;
+        }
+        JSONObject detailContent = new JSONObject();
+        detailContent.put("medical_text_type", medicalTextType);
+        detailContent.put("content", moveText);
+        detailContent.put("detail_title", sign);
+        detailContent.put("wardDate", wardDate);
+        crfContent.add(detailContent);
+    }
+
+    /**
+     * 处理全部查房记录
+     *
+     * @param jsonObject
+     * @param inputInfo
+     */
+    public void putWardRoundCrfData(JSONObject jsonObject, InputInfo inputInfo, int serious) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return;
+        }
+        String wardDate = jsonObject.getString("wardDate");
+        String detailTitle = jsonObject.getString("detail_title");
+        EntityProcessThreeLevelWard entityProcessThreeLevelWard = new EntityProcessThreeLevelWard();
+        ThreeLevelWardLabel threeLevelWardLabel = entityProcessThreeLevelWard.extractEntity(aiOut);
+        threeLevelWardLabel.setTitle(detailTitle);
+        threeLevelWardLabel.setSerious(serious);
+        ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+        //2020/08/20新增所有查房记录抽取:实验室检查、辅助检查、药品等
+        Pattern p = Pattern.compile("\\d+");
+        Matcher matcher = p.matcher(detailTitle);
+        if (matcher.find()) {
+            String num = matcher.group(0);
+            int n = Integer.parseInt(num);
+            ThreeLevelWardDoc doc = threeLevelWardDoc.getAllDoctorWradDocs().get(n);
+            if (doc.getThreeLevelWardLabel().size() > 0) {
+                doc.getThreeLevelWardLabel().add(threeLevelWardLabel);
+            } else {
+                threeLevelWardDoc.getAllDoctorWradDocs().get(n).setThreeLevelWardLabel(Lists.newArrayList(threeLevelWardLabel));
+            }
+        }
+        List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+        for (ThreeLevelWardDoc wardDoc : allDoctorWradDocs) {
+            String date = wardDoc.getStructureMap().get("查房日期");
+            if (StringUtil.isNotBlank(date) && StringUtil.isNotBlank(wardDate) && date.equals(wardDate)) {
+                wardDoc.getThreeLevelWardLabel().add(threeLevelWardLabel);
+                break;
+            }
+        }
+    }
+
+    /**
+     * 处理主治主任首次、末次查房
+     *
+     * @param jsonObject
+     * @return
+     */
+    public ThreeLevelWardLabel putWardRoundCrfData(JSONObject jsonObject) {
+        JSONObject aiOut = loadEntity(jsonObject, entityRelationObject, outputs, content);
+        if (aiOut == null) {
+            return new ThreeLevelWardLabel();
+        }
+        String detailTitle = jsonObject.getString("detail_title");
+        EntityProcessThreeLevelWard entityProcessThreeLevelWard = new EntityProcessThreeLevelWard();
+        ThreeLevelWardLabel threeLevelWardLabel = entityProcessThreeLevelWard.extractEntity(aiOut);
+        threeLevelWardLabel.setTitle(detailTitle);
+        return entityProcessThreeLevelWard.extractEntity(aiOut);
+
+    }
+
+    /**
+     * 存放每条疑难病例讨论记录后第一条查房记录
+     *
+     * @param inputInfo
+     * @param allDoctorWradDocs
+     * @return
+     */
+    public List<Map<String, String>> putDirectorDifficultRecord(InputInfo inputInfo, List<ThreeLevelWardDoc> allDoctorWradDocs) {
+        List<Map<String, String>> record = new ArrayList<>();
+        List<DifficultCaseDiscussDoc> difficultCaseDiscussDocs = inputInfo.getDifficultCaseDiscussDocs(); //疑难病例讨论记录
+        Map<Date, Map<String, String>> dateRecord = new TreeMap<>(new Comparator<Date>() {
+            @Override
+            public int compare(Date o1, Date o2) {
+                // 升序排列
+                return o1.compareTo(o2);
+            }
+        });//按时间key排序,存放抢救记录、查房记录
+        String recordTime = "", title = "";
+        for (DifficultCaseDiscussDoc difficultCaseDiscussDoc : difficultCaseDiscussDocs) {
+            Map<String, String> difficultCaseDiscussStructureMap = difficultCaseDiscussDoc.getStructureMap();
+            recordTime = difficultCaseDiscussStructureMap.get("讨论日期");
+            Date recordDate = null;
+            if (StringUtil.isNotEmpty(recordTime)) {
+                recordDate = StringUtil.parseDateTime(recordTime);
+            }
+            if (recordDate == null) {
+                continue;
+            }
+            dateRecord.put(recordDate, difficultCaseDiscussStructureMap);
+        }
+        dateRecord = extractUnique(dateRecord);
+        for (ThreeLevelWardDoc threeLevelWardDoc : allDoctorWradDocs) {
+            Map<String, String> rescueStructureMap = threeLevelWardDoc.getStructureMap();
+            recordTime = rescueStructureMap.get("查房日期");
+            title = CatalogueUtil.subTitle(rescueStructureMap.get("查房标题"));
+            Date recordDate = StringUtil.parseDateTime(recordTime);
+            if (recordDate == null || StringUtil.isBlank(title) || !title.contains(Content.director)) {//只存副高以上查房记录) {
+                continue;
+            }
+            dateRecord.put(recordDate, rescueStructureMap);
+        }
+        List<Map<String, String>> dateRecordList = new ArrayList<>(dateRecord.values());
+        //如果最后一条是疑难病例讨论记录,则之后肯定没有查房记录
+        if (dateRecordList.get(dateRecordList.size() - 1).containsKey("讨论日期")) {
+            record = new ArrayList<>();
+            return record;
+        }
+        for (int i = 0; i < dateRecordList.size(); i++) {
+            if (i != dateRecordList.size() - 1) {
+                //当前为疑难病例讨论记录
+                if (!dateRecordList.get(i).containsKey("讨论日期")) {
+                    continue;
+                }
+                //疑难病例讨论记录下一条不是查房记录则清空list
+                if (!dateRecordList.get(i + 1).containsKey("查房日期")) {
+                    record = new ArrayList<>();
+                    break;
+                } else {
+                    //疑难病例讨论记录下一条是查房记录,添加进list(这条疑难病例讨论记录后全部查房记录的第一条)
+                    record.add(dateRecordList.get(i + 1));
+                }
+            }
+        }
+        return record;
+    }
+
+    /**
+     * 存放每条抢救记录后第一条
+     *
+     * @param inputInfo
+     * @param allDoctorWradDocs
+     * @return
+     */
+    public List<Map<String, String>> putDirectorRescueRecord(InputInfo inputInfo, List<ThreeLevelWardDoc> allDoctorWradDocs) {
+        List<Map<String, String>> record = new ArrayList<>();
+        List<RescueDoc> rescueDocs = inputInfo.getRescueDocs(); //抢救记录
+        Map<Date, Map<String, String>> dateRecord = new TreeMap<>(new Comparator<Date>() {
+            @Override
+            public int compare(Date o1, Date o2) {
+                // 升序排列
+                return o1.compareTo(o2);
+            }
+        });//按时间key排序,存放抢救记录、查房记录
+        String recordTime = "", title = "";
+        for (RescueDoc rescueDoc : rescueDocs) {
+            Map<String, String> rescueStructureMap = rescueDoc.getStructureMap();
+            recordTime = rescueStructureMap.get("抢救结束时间");
+            if (recordTime == null) {
+                continue;
+            }
+            Date recordDate = StringUtil.parseDateTime(recordTime);
+            if (recordDate == null) {
+                continue;
+            }
+            dateRecord.put(recordDate, rescueStructureMap);
+        }
+        dateRecord = extractUnique(dateRecord);
+        for (ThreeLevelWardDoc threeLevelWardDoc : allDoctorWradDocs) {
+            Map<String, String> rescueStructureMap = threeLevelWardDoc.getStructureMap();
+            recordTime = rescueStructureMap.get("查房日期");
+            title = CatalogueUtil.subTitle(rescueStructureMap.get("查房标题"));
+            Date recordDate = StringUtil.parseDateTime(recordTime);
+            if (recordDate == null || StringUtil.isBlank(title) || !title.contains(Content.director)) {//只存副高以上查房记录) {
+                continue;
+            }
+            dateRecord.put(recordDate, rescueStructureMap);
+        }
+        List<Map<String, String>> dateRecordList = new ArrayList<>(dateRecord.values());
+        //如果最后一条是抢救记录,则之后肯定没有查房记录
+        if (ListUtil.isNotEmpty(dateRecordList) && dateRecordList.get(dateRecordList.size() - 1).containsKey("抢救结束时间")) {
+            record = new ArrayList<>();
+            return record;
+        }
+        for (int i = 0; i < dateRecordList.size(); i++) {
+            if (i != dateRecordList.size() - 1) {
+                //当前为抢救记录
+                if (!dateRecordList.get(i).containsKey("抢救结束时间")) {
+                    continue;
+                }
+                //抢救记录下一条不是查房记录则清空list
+                if (!dateRecordList.get(i + 1).containsKey("查房日期")) {
+                    record = new ArrayList<>();
+                    break;
+                } else {
+                    //抢救记录下一条是查房记录,添加进list(抢救记录后全部查房记录的第一条)
+                    record.add(dateRecordList.get(i + 1));
+                }
+            }
+        }
+        return record;
+    }
+
+    /**
+     * 抽取24小时内第一条记录
+     *
+     * @param dateRecord
+     */
+    private Map<Date, Map<String, String>> extractUnique(Map<Date, Map<String, String>> dateRecord) {
+        Map<Date, Map<String, String>> record = new TreeMap<>(new Comparator<Date>() {
+            @Override
+            public int compare(Date o1, Date o2) {
+                // 升序排列
+                return o1.compareTo(o2);
+            }
+        });
+        Date lastDate = null;
+        for (Map.Entry<Date, Map<String, String>> dateRecordEntry : dateRecord.entrySet()) {
+            Date date = dateRecordEntry.getKey();
+            if (lastDate == null || CatalogueUtil.compareTime(lastDate, date, (long) (24 * 60))) {
+                lastDate = date;
+                record.put(date, dateRecordEntry.getValue());
+            }
+        }
+        return record;
+    }
+}

+ 205 - 0
structure-center/src/main/java/com/lantone/structure/ai/model/ConflictFinder.java

@@ -0,0 +1,205 @@
+package com.lantone.structure.ai.model;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @Description: 找出冲突
+ * @Author: HUJING
+ * @Date: 2020/8/2 15:04
+ */
+public class ConflictFinder {
+
+    private static Set<String> ignoreWords;
+    private static Set<String> negativeWords;
+    private static Map<String, String> conflictWordPairMap;
+
+    static {
+        ignoreWords = Sets.newHashSet("部", "侧");
+        negativeWords = Sets.newHashSet("无", "无殊", "否认", "不伴", "未找到",
+                "未萌出", "未见", "未", "不", "不伴有", "非", "不明显", "无明显");
+        conflictWordPairMap = Maps.newHashMap();
+        conflictWordPairMap.put("可", "差");
+        conflictWordPairMap.put("尚可", "差");
+    }
+
+
+    /**
+     * 搜索和配对
+     *
+     * @param invertedIndexTableCheck   专科检查的倒排索引
+     * @param invertedIndexTablePresent 现病史的倒排索引
+     */
+    public List<EntityBlock[]> match(Map<String, Set<EntityBlock>> invertedIndexTableCheck,
+                                     Map<String, Set<EntityBlock>> invertedIndexTablePresent) {
+
+        List<EntityBlock[]> entityBlockPairs = Lists.newArrayList();
+        Set<String> existedIdPairs = Sets.newHashSet();  // 去除多搜索词搜到同一组实体块对引起的重复
+        invertedIndexTableCheck.forEach((char_, entityBlockSetCheck) -> {
+            invertedIndexTablePresent.getOrDefault(char_, Sets.newHashSet()).forEach(entityBlockPresent -> {
+                entityBlockSetCheck.forEach(entityBlockCheck -> {
+                    String idPair = "" + entityBlockCheck.getId() + "_" + entityBlockPresent.getId();
+                    if (!existedIdPairs.contains(idPair)) {
+                        entityBlockPairs.add(new EntityBlock[] { entityBlockCheck, entityBlockPresent });
+
+                        existedIdPairs.add(idPair);
+                    }
+                });
+            });
+        });
+
+        return entityBlockPairs;
+    }
+
+    /**
+     * 字符串1没在字符串2中的子词, // 并不是很严格意义上的那种,不过可以用
+     *
+     * @param word1 字符串1
+     * @param word2 字符串2
+     * @return 字符串列表
+     */
+    private List<String> subWordsInWord1NotInWord2(String word1, String word2) {
+
+        StringBuilder inWord1NotInWord2 = new StringBuilder();
+        Map<String, Integer> word2Map = Maps.newHashMap();
+        for (int i = 0; i < word2.length(); i++) {
+            word2Map.put(word2.substring(i, i + 1), 1);
+        }
+
+        for (int i = 0; i < word1.length(); i++) {
+            String char_ = word1.substring(i, i + 1).trim();
+            if (!"".equals(char_) && !ignoreWords.contains(char_)) {
+                if (!word2Map.containsKey(char_)) {
+                    inWord1NotInWord2.append(char_);
+                } else {
+                    inWord1NotInWord2.append("_s_");  // _s_ 作为分隔符
+                }
+            }
+        }
+        List<String> subWords = Lists.newArrayList();
+        for (String subWord : inWord1NotInWord2.toString().split("_s_")) {
+            if (!"".equals(subWord.trim())) {
+                subWords.add(subWord.trim());
+            }
+
+        }
+        return subWords;
+    }
+
+    /**
+     * 只缺少一个阴性词
+     *
+     * @param word_1 词1
+     * @param word_2 词2
+     * @return 冲突则ture,否则false
+     */
+    private boolean onlyLackOfNegativeWord(String word_1, String word_2) {
+
+        List<String> subWords_1 = subWordsInWord1NotInWord2(word_1, word_2);
+        List<String> subWords_2 = subWordsInWord1NotInWord2(word_2, word_1);
+        if (subWords_1.size() == 1 && subWords_2.size() == 0) {
+            return negativeWords.contains(subWords_1.get(0));
+        }
+        if (subWords_2.size() == 1 && subWords_1.size() == 0) {
+            return negativeWords.contains(subWords_2.get(0));
+        }
+
+        return false;
+    }
+
+    /**
+     * 不同的只有冲突词
+     *
+     * @param word_1 词1
+     * @param word_2 词2
+     * @return 冲突则ture,否则false
+     */
+    private boolean onlyDifferentWithConflictWords(String word_1, String word_2) {
+
+        List<String> subWords_1 = subWordsInWord1NotInWord2(word_1, word_2);
+        List<String> subWords_2 = subWordsInWord1NotInWord2(word_2, word_1);
+        if (subWords_1.size() == 1 && subWords_2.size() == 1) {
+            return conflictWordPairMap.getOrDefault(subWords_1.get(0), "").equals(subWords_2.get(0)) ||
+                    conflictWordPairMap.getOrDefault(subWords_2.get(0), "").equals(subWords_1.get(0));
+
+        }
+        return false;
+    }
+
+    /**
+     * 是否冲突
+     *
+     * @param entityBlock_1 实体块1
+     * @param entityBlock_2 实体块2
+     * @return 冲突true,否则false
+     */
+    public boolean isConflict(EntityBlock entityBlock_1, EntityBlock entityBlock_2) {
+
+        StringBuilder word1Builder = new StringBuilder();
+        entityBlock_1.getEntityWords().forEach(word1Builder::append);
+        String word_1 = word1Builder.toString();
+
+        StringBuilder word2Builder = new StringBuilder();
+        entityBlock_2.getEntityWords().forEach(word2Builder::append);
+        String word_2 = word2Builder.toString();
+
+        if (word_1.length() == 0 || word_2.length() == 0) {
+            return false;
+        }
+
+        return onlyLackOfNegativeWord(word_1, word_2) || onlyDifferentWithConflictWords(word_1, word_2);
+    }
+
+    /**
+     * 获取位置
+     *
+     * @param entityBlock_1 实体块1
+     * @param entityBlock_2 实体块2
+     * @return List<int [ ]> 对
+     */
+    public Object[] getPositions(EntityBlock entityBlock_1, EntityBlock entityBlock_2) {
+        return new Object[] { entityBlock_1.getPositions(), entityBlock_2.getPositions() };
+    }
+
+
+    /**
+     * 找出冲突的位置
+     *
+     * @param checkPairs   专科检查实体和关系列表
+     * @param presentPairs 现病史实体和关系列表
+     * @return 冲突位置组对列表
+     */
+    public List<Object[]> findConflictPositions(Object[] checkPairs, Object[] presentPairs) {
+        List<Lemma> checkLemmas = (List<Lemma>) checkPairs[0];
+        List<Relation> checkRelations = (List<Relation>) checkPairs[1];
+
+        List<Lemma> presentLemmas = (List<Lemma>) presentPairs[0];
+        List<Relation> presentRelations = (List<Relation>) presentPairs[1];
+
+        InvertedIndexTableBuilder checkInvertedIndexTableBuilder = new InvertedIndexTableBuilder(checkLemmas, checkRelations);
+        InvertedIndexTableBuilder presentInvertedIndexTableBuilder = new InvertedIndexTableBuilder(presentLemmas, presentRelations);
+        Map<String, Set<EntityBlock>> checkInvertedIndexTable = checkInvertedIndexTableBuilder.generateInvertedIndexTablePipeline();
+        Map<String, Set<EntityBlock>> presentInvertedIndexTable = presentInvertedIndexTableBuilder.generateInvertedIndexTablePipeline();
+
+        List<EntityBlock[]> entityBlockPairs = match(checkInvertedIndexTable, presentInvertedIndexTable);
+
+        List<Object[]> conflictPositions = Lists.newArrayList();
+        entityBlockPairs.forEach(entityBlockPair -> {
+            EntityBlock entityBlock_1 = entityBlockPair[0];
+            EntityBlock entityBlock_2 = entityBlockPair[1];
+            boolean conflict = isConflict(entityBlock_1, entityBlock_2);
+            // TODO: 删除调
+            //System.out.println("" + conflict + ":" + entityBlock_1 + " ---> " + entityBlock_2);
+            if (conflict) {
+                conflictPositions.add(getPositions(entityBlock_1, entityBlock_2));
+                conflictPositions.add(new Object[]{entityBlock_1,entityBlock_2});
+            }
+        });
+        return conflictPositions;
+    }
+}

+ 21 - 0
structure-center/src/main/java/com/lantone/structure/ai/model/CrfOut.java

@@ -0,0 +1,21 @@
+package com.lantone.structure.ai.model;
+
+import com.lantone.structure.model.entity.*;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+public class CrfOut {
+    List<Clinical> symptoms = new ArrayList<Clinical>();//症状
+    List<Vital> vitals = new ArrayList<>();
+    List<Pacs> pacses = new ArrayList<>();
+    List<GeneralDesc> generals = new ArrayList<>();//基本情况
+    List<Lis> lises = new ArrayList<>();
+    List<Diag> diags = new ArrayList<>();
+    List<Past> pasts = new ArrayList<>();
+
+}

+ 27 - 0
structure-center/src/main/java/com/lantone/structure/ai/model/EntityBlock.java

@@ -0,0 +1,27 @@
+package com.lantone.structure.ai.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * @Description:
+ * @Author: HUJING
+ * @Date: 2020/7/31 11:19
+ */
+@Setter
+@Getter
+public class EntityBlock {
+    private List<String> entityWords;
+    private List<String> entityTypes;
+    private List<int[]> positions;
+    private String genre;
+    private String searchWord;
+    private Integer id;
+
+    @Override
+    public String toString() {
+        return entityWords.toString().replaceAll("[\\[\\]]","");
+    }
+}

+ 267 - 0
structure-center/src/main/java/com/lantone/structure/ai/model/EntityEnum.java

@@ -0,0 +1,267 @@
+package com.lantone.structure.ai.model;
+
+/**
+ * @Description:
+ * @Author: HUJING
+ * @Date: 2019/12/17 9:58
+ */
+public enum EntityEnum {
+    CLINICAL_FEATURE("临床表现"), DIEASE("疾病名称"), BODY("身体部位"), SIGN("体征"), INDEX_VALUE("指标值"),
+    LABORATORY("实验室检查"), LABORATORY_VALUE("实验室检查值"), AUXILIARY_EXAMINATION("辅助检查"), AUXILIARY_DESCRIPT("辅助检查描述"),
+    NEGATIVE("否定"), POSSIBLE("可能的"), TIME("时间"), CAUSE("诱因"), MODIFICATION("修饰"),
+    PROPERTY("性质"), DEGREE("程度"), AGGRAVATE("加重情况"), RELIEF("缓解情况"), BEHOSPITALIZEDWAY("入院途径"),
+    TREND("趋势"), FREQUENCY("频率"), QUANTITY("数量"), SIZE("尺寸"), CURE("治疗"), TREAT_MENT("治疗或治疗目的"), DRUG("药物名称"),
+    DOSE("药品剂量"), OPERATION("手术名称"), GENERAL("一般情况"), GENERAL_DESCRIPT("一般情况描述"),
+    OPERATION_KEYWORD("手术史"), OPERATION_RESULT("手术结果"), INJURY("外伤史"), ALLERGY("过敏"),
+    FOOD_ALLERGY("食物过敏原"), DRUG_ALLERGY("药物过敏原"), ALLERGY_SYMPTOM("过敏表现"), BLOOD_TRANSFUSION("输血史"),
+    TRANSFUSION_REACTION("输血反应"), VACCINATION("预防接种史"), DISEASE_KEYWORD("疾病史"), INFECTIOUS_KEYWORD("传染病史"),
+    UNKNOWN("情况不详"), HEALTH("健康情况"), AGE("年龄"), SMOKING_HISTORY("吸烟史"),
+    HISTORY_OF_ALCOHOL_INTAKE("饮酒史"), USAGE("用量"), MENSES("月经"), LEUKORRHEA("白带"),
+    BIRTH_HIS("生育情况"), CONJUGAL_RELATION("夫妻关系"), RELATIVES("家属"), GROUP_CONSULTATION("会诊"), ORGANISM("生物体"),
+    OCCUPATION("职业"), LOCATION("地点"), DEAD("死亡"), DEAD_REASON("死亡原因"), TUMOUR("肿瘤病史"),
+    SIMILAR_DISEASE_KEYWORD("相似疾病"), GENETIC_DISEASE_KEYWORD("家族遗传病"), EPIDEMIC_AREA_HISTORY("疫区史"), SPECIAL_HOBBY("特殊嗜好"),
+    CONTACT_HISTORY("接触史"), MARITAL_HISTORY("冶游史"), MARITAL_STATUS("婚姻情况"), MARRYIAGE("结婚年龄"), NEAR_RELATION("近亲史"),
+    CURE_AIM("治疗目的"), OTHER("其他"), OUTERCOURTYARD("外院"), NURSING_LEVEL("护理级别"), CHIEF("主诉"), NOTES("注意事项"),
+    KEY_WORD_FOR_DOCTOR_ADVICES("出院医嘱标题"), DOCTORADVICE("医嘱"), KEY_WORD_FOR_PART("大标题"), OUTCOME("转归情况"),
+    PHYSICAL_EXAMINATION("查体"), TITLE_FOR_SIGN("查体标题"), TITLE_FOR_DIAG("诊断标题"), TITLE_FOR_DIAG_BASIS("诊断依据标题"),
+    TITLE_FOR_DIFF("鉴别诊断标题"), TITLE_FOR_TREAT("诊疗计划标题"), TITLE("标题"), TREATMENT_PLAN("诊疗计划"),
+    TITLE_OF_OPERATIVE_FINDINGS("手术经过标题"), TITLE_OF_MEASURES_AFTER_OP("术后处理措施标题"),
+    TITLE_OF_RISK_AFTER_OP("术后风险标题"), TITLE_OF_ATTENTION_AFTER_OP("术后注意事项标题"), VITAL("生命体征"),
+    BETTER_FINDING("好转表现"), OUTCOME_TO_BETTER("转归情况-好转"), OUTCOME_CURE("转归情况-治愈"), POSITIVE_FINDING("阳性表现"),
+    INSPECTION_ITEMS("检查项目"), DISCHARGE_MODE("出院方式"), LABORATORY_PACKAGE("实验室检查套餐"), LABORATORY_RESULTS("实验室检查结果"),
+    AUXILIARY_EXAMINATION_RESULTS("辅检结果"), CONSUMPTION("用量-查房"), USAGE_WARD_ROUND("用法"), STOP("停用"),
+    REASONS_FOR_ANTIBIOTIC("抗生素使用原因"),CHECK_TIME("检查时间");
+
+    private String value;
+
+    EntityEnum(String value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return value;
+    }
+
+    public static EntityEnum parseOfValue(String value) {
+        if (value == null) {
+            return EntityEnum.OTHER;
+        }
+        EntityEnum entityEnum = EntityEnum.OTHER;
+        switch (value) {
+            case "临床表现":
+                entityEnum = EntityEnum.CLINICAL_FEATURE;
+                break;
+            case "疾病名称":
+                entityEnum = EntityEnum.DIEASE;
+                break;
+            case "身体部位":
+                entityEnum = EntityEnum.BODY;
+                break;
+            case "体征":
+                entityEnum = EntityEnum.SIGN;
+                break;
+            case "指标值":
+                entityEnum = EntityEnum.INDEX_VALUE;
+                break;
+            case "实验室检查":
+                entityEnum = EntityEnum.LABORATORY;
+                break;
+            case "实验室检查值":
+                entityEnum = EntityEnum.LABORATORY_VALUE;
+                break;
+            case "辅助检查":
+                entityEnum = EntityEnum.AUXILIARY_EXAMINATION;
+                break;
+            case "辅助检查描述":
+                entityEnum = EntityEnum.AUXILIARY_DESCRIPT;
+                break;
+            case "否定":
+                entityEnum = EntityEnum.NEGATIVE;
+                break;
+            case "可能的":
+                entityEnum = EntityEnum.POSSIBLE;
+                break;
+            case "时间":
+                entityEnum = EntityEnum.TIME;
+                break;
+            case "诱因":
+                entityEnum = EntityEnum.CAUSE;
+                break;
+            case "修饰":
+                entityEnum = EntityEnum.MODIFICATION;
+                break;
+            case "趋势":
+                entityEnum = EntityEnum.TREND;
+                break;
+            case "频率":
+                entityEnum = EntityEnum.FREQUENCY;
+                break;
+            case "数量":
+                entityEnum = EntityEnum.QUANTITY;
+                break;
+            case "尺寸":
+                entityEnum = EntityEnum.SIZE;
+                break;
+            case "治疗":
+                entityEnum = EntityEnum.CURE;
+                break;
+            case "药物名称":
+                entityEnum = EntityEnum.DRUG;
+                break;
+            case "药品剂量":
+                entityEnum = EntityEnum.DOSE;
+                break;
+            case "手术名称":
+                entityEnum = EntityEnum.OPERATION;
+                break;
+            case "一般情况":
+                entityEnum = EntityEnum.GENERAL;
+                break;
+            case "一般情况描述":
+                entityEnum = EntityEnum.GENERAL_DESCRIPT;
+                break;
+            case "手术史":
+                entityEnum = EntityEnum.OPERATION_KEYWORD;
+                break;
+            case "手术结果":
+                entityEnum = EntityEnum.OPERATION_RESULT;
+                break;
+            case "外伤史":
+                entityEnum = EntityEnum.INJURY;
+                break;
+            case "过敏":
+                entityEnum = EntityEnum.ALLERGY;
+                break;
+            case "食物过敏原":
+                entityEnum = EntityEnum.FOOD_ALLERGY;
+                break;
+            case "药物过敏原":
+                entityEnum = EntityEnum.DRUG_ALLERGY;
+                break;
+            case "过敏表现":
+                entityEnum = EntityEnum.ALLERGY_SYMPTOM;
+                break;
+            case "输血史":
+                entityEnum = EntityEnum.BLOOD_TRANSFUSION;
+                break;
+            case "输血反应":
+                entityEnum = EntityEnum.TRANSFUSION_REACTION;
+                break;
+            case "预防接种史":
+                entityEnum = EntityEnum.VACCINATION;
+                break;
+            case "疾病史":
+                entityEnum = EntityEnum.DISEASE_KEYWORD;
+                break;
+            case "传染病史":
+                entityEnum = EntityEnum.INFECTIOUS_KEYWORD;
+                break;
+            case "情况不详":
+                entityEnum = EntityEnum.UNKNOWN;
+                break;
+            case "健康状况":
+                entityEnum = EntityEnum.HEALTH;
+                break;
+            case "年龄":
+                entityEnum = EntityEnum.AGE;
+                break;
+            case "吸烟史":
+                entityEnum = EntityEnum.SMOKING_HISTORY;
+                break;
+            case "饮酒史":
+                entityEnum = EntityEnum.HISTORY_OF_ALCOHOL_INTAKE;
+                break;
+            case "用量":
+                entityEnum = EntityEnum.USAGE;
+                break;
+            case "月经":
+                entityEnum = EntityEnum.MENSES;
+                break;
+            case "白带":
+                entityEnum = EntityEnum.LEUKORRHEA;
+                break;
+            case "生育情况":
+                entityEnum = EntityEnum.BIRTH_HIS;
+                break;
+            case "夫妻关系":
+                entityEnum = EntityEnum.CONJUGAL_RELATION;
+                break;
+            case "家属":
+                entityEnum = EntityEnum.RELATIVES;
+                break;
+            case "会诊":
+                entityEnum = EntityEnum.GROUP_CONSULTATION;
+                break;
+            case "生物体":
+                entityEnum = EntityEnum.ORGANISM;
+                break;
+            case "职业":
+                entityEnum = EntityEnum.OCCUPATION;
+                break;
+            case "地点":
+                entityEnum = EntityEnum.LOCATION;
+                break;
+            case "死亡":
+                entityEnum = EntityEnum.DEAD;
+                break;
+            case "死亡原因":
+                entityEnum = EntityEnum.DEAD_REASON;
+                break;
+            case "相似疾病":
+                entityEnum = EntityEnum.SIMILAR_DISEASE_KEYWORD;
+                break;
+            case "家族遗传病":
+                entityEnum = EntityEnum.GENETIC_DISEASE_KEYWORD;
+                break;
+            case "疫区史":
+                entityEnum = EntityEnum.EPIDEMIC_AREA_HISTORY;
+                break;
+            case "特殊嗜好":
+                entityEnum = EntityEnum.SPECIAL_HOBBY;
+                break;
+            case "接触史":
+                entityEnum = EntityEnum.CONTACT_HISTORY;
+                break;
+            case "冶游史":
+                entityEnum = EntityEnum.MARITAL_HISTORY;
+                break;
+            case "婚姻情况":
+                entityEnum = EntityEnum.MARITAL_STATUS;
+                break;
+            case "治疗目的":
+                entityEnum = EntityEnum.CURE_AIM;
+                break;
+            case "检查项目":
+                entityEnum = EntityEnum.INSPECTION_ITEMS;
+                break;
+            case "出院方式":
+                entityEnum = EntityEnum.DISCHARGE_MODE;
+                break;
+            case "实验室检查套餐":
+                entityEnum = EntityEnum.LABORATORY_PACKAGE;
+                break;
+            case "实验室检查结果":
+                entityEnum = EntityEnum.LABORATORY_RESULTS;
+                break;
+            case "辅检结果":
+                entityEnum = EntityEnum.AUXILIARY_EXAMINATION_RESULTS;
+                break;
+            case "用量-查房":
+                entityEnum = EntityEnum.CONSUMPTION;
+                break;
+            case "用法":
+                entityEnum = EntityEnum.USAGE_WARD_ROUND;
+                break;
+            case "停用":
+                entityEnum = EntityEnum.STOP;
+                break;
+            case "抗生素使用原因":
+                entityEnum = EntityEnum.REASONS_FOR_ANTIBIOTIC;
+                break;
+            case "检查时间":
+                entityEnum = EntityEnum.CHECK_TIME;
+                break;
+        }
+        return entityEnum;
+    }
+}

+ 282 - 0
structure-center/src/main/java/com/lantone/structure/ai/model/InvertedIndexTableBuilder.java

@@ -0,0 +1,282 @@
+package com.lantone.structure.ai.model;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @Description:
+ * @Author: HUJING
+ * @Date: 2020/8/2 12:25
+ */
+public class InvertedIndexTableBuilder {
+    private static Set<String> selectedLonelyEntityTypes;  // 选定的孤独实体类型
+    private static Set<String> selectedRelationTypes;  // 选定的关系类型
+    // 选定的多步关系模式,比如:身体部位->临床表现<-否定
+    private static Set<Set<String>> selectedMultiStepRelationTypes;
+
+    private Map<Integer, Lemma> idEntityMap;
+    private List<Relation> relations;
+    private List<Lemma> lonelyEntityList;
+
+    private static Set<String> removeIndexWords; // 被移除的搜索词
+
+    static {  // 把该模块从现病史和专科检查扩展到别的比较中需要修改的地方
+        selectedLonelyEntityTypes = Sets.newHashSet("临床表现", "修饰");
+        selectedRelationTypes = Sets.newHashSet("身体部位-临床表现",
+                "一般情况-一般情况描述", "否定-临床表现");
+        selectedMultiStepRelationTypes = Sets.newHashSet(Sets.newHashSet());  // 暂且没用上
+
+        removeIndexWords = Sets.newHashSet();
+
+        for (int i = 0; i < 10; i++) {
+            removeIndexWords.add("" + i);
+        }
+
+        for (int i = 0; i < 10; i++) {  //数字
+            removeIndexWords.add(String.valueOf(i));
+        }
+
+        for (int i = 'a'; i <= 'z'; i++) {  //英文词
+            removeIndexWords.add(String.valueOf((char) i));
+            removeIndexWords.add(String.valueOf((char) i).toUpperCase());
+        }
+
+        List<String> punctuations = Lists.newArrayList();//添加标点符号
+        List<String> positionWords = Lists.newArrayList();//添加方位词
+        List<String> emrWords = Lists.newArrayList("无");//添加一些病例中无用的词
+
+        List<String> words = new ArrayList<>();
+        words.addAll(emrWords);
+        words.addAll(punctuations);
+        words.addAll(positionWords);
+
+        removeIndexWords.addAll(words);
+    }
+
+    public InvertedIndexTableBuilder(List<Lemma> lemmas, List<Relation> relations) {
+        idEntityMap = Maps.newHashMap();
+        for (Lemma lemma : lemmas) {
+            idEntityMap.put(lemma.getId(), lemma);
+        }
+
+        this.relations = relations;
+
+    }
+
+    /**
+     * 过滤实体和关系
+     */
+    private void filterEntitiesAndRelations() {
+
+        // 实体删除规则:没在关系中,且其实体类型没在已选的孤独实体类型中
+        Map<Integer, Lemma> newIdEntityMap = Maps.newHashMap();
+        idEntityMap.forEach((id, lemma) -> {
+            if (selectedLonelyEntityTypes.contains(lemma.getProperty())) {
+                newIdEntityMap.put(id, lemma);
+            }
+        });
+
+        List<Relation> filteredRelations = Lists.newArrayList();
+        Set<Integer> entityIdInRelationSet = Sets.newHashSet();
+        for (Relation relation : relations) {
+            Integer fromId = relation.getFrom();
+            Integer toId = relation.getTo();
+            if (selectedRelationTypes.contains(relation.getRelationName())) {
+                filteredRelations.add(relation);
+                newIdEntityMap.put(fromId, idEntityMap.get(fromId));
+                newIdEntityMap.put(toId, idEntityMap.get(toId));
+            }
+
+            entityIdInRelationSet.add(fromId);
+            entityIdInRelationSet.add(toId);
+        }
+
+        this.idEntityMap = newIdEntityMap;
+        this.relations = filteredRelations;
+        this.lonelyEntityList = Lists.newArrayList();
+        this.idEntityMap.forEach((id, lemma) -> {
+            if (!entityIdInRelationSet.contains(id)) { // 不在关系中的实体为孤独实体
+                this.lonelyEntityList.add(lemma);
+            }
+        });
+
+    }
+
+    /**
+     * 分组有关系的实体id对
+     *
+     * @param idPairs 实体id对
+     * @return 实体id对组
+     */
+    public static List<List<Integer>> groupIdPairs(List<Integer[]> idPairs) {
+
+        Map<Integer, Set<Integer>> idRelatedIdsMap = Maps.newHashMap();
+        for (Integer[] idPair : idPairs) {
+            if (idPair.length == 2) {
+                Integer fromId = idPair[0];
+                Integer toId = idPair[1];
+                Set<Integer> fromIds = idRelatedIdsMap.getOrDefault(fromId, Sets.newHashSet());
+                Set<Integer> toIds = idRelatedIdsMap.getOrDefault(toId, Sets.newHashSet());
+                fromIds.addAll(toIds);
+                fromIds.add(fromId);
+                fromIds.add(toId);
+                fromIds.forEach(id -> {  // 更新每个id所关联的ids
+                    idRelatedIdsMap.put(id, fromIds);
+                });
+
+            }
+        }
+
+        List<List<Integer>> idGroups = Lists.newArrayList();
+        Set<Integer> usedIds = Sets.newHashSet();
+
+        idRelatedIdsMap.forEach((id, ids) -> {
+            if (!usedIds.contains(id)) {
+                List<Integer> idsList = Lists.newArrayList();
+                idsList.addAll(ids);
+                idsList.sort(Integer::compareTo);
+                idGroups.add(idsList);
+
+                usedIds.addAll(ids);  // 避免重复
+            }
+        });
+
+        return idGroups;
+    }
+
+    /**
+     * 用关系合并实体
+     *
+     * @return 实体组列表
+     */
+    private List<List<Lemma>> mergeEntitiesByRelations() {
+
+        List<List<Lemma>> entityGroups = Lists.newArrayList();
+
+        // 孤独实体
+        for (Lemma lemma : lonelyEntityList) {
+            entityGroups.add(Lists.newArrayList(lemma));
+        }
+
+        List<Integer[]> idPairs = Lists.newArrayList();
+        relations.forEach(relation -> {
+            idPairs.add(new Integer[] { relation.getFrom(), relation.getTo() });
+        });
+
+        List<List<Integer>> idGroups = groupIdPairs(idPairs);
+        idGroups.forEach(idGroup -> {
+            if (idGroup.size() == 2) {
+                List<Lemma> entityGroup = Lists.newArrayList();
+                idGroup.forEach(id -> {
+                    entityGroup.add(idEntityMap.get(id));
+                });
+                entityGroups.add(entityGroup);
+            } else if (idGroup.size() == 3) {
+                // 将来会用一些模式去匹配,比如:(腹,压痛,反跳痛) 本质是=> 腹->压痛, 腹->反跳痛, 需要拆开成两组
+
+                List<Lemma> entityGroup = Lists.newArrayList();
+                idGroup.forEach(id -> {
+                    entityGroup.add(idEntityMap.get(id));
+                });
+                entityGroups.add(entityGroup);
+            } else {
+                // 将来会用一些模式去配,这里先留下
+            }
+        });
+
+        return entityGroups;
+    }
+
+    /**
+     * 设置一个实体块对象
+     *
+     * @param entityGroup 实体组
+     * @param id          实体块id
+     * @return 实体块对象
+     */
+    private EntityBlock setEntityBlock(List<Lemma> entityGroup, Integer id) {
+
+        List<String> entityWords = Lists.newArrayList();
+        List<String> entityTypes = Lists.newArrayList();
+        List<int[]> positions = Lists.newArrayList();
+        entityGroup.forEach(lemma -> {
+            entityWords.add(lemma.getText());
+            entityTypes.add(lemma.getProperty());
+            positions.add(new int[] { lemma.getFrom(), lemma.getTo() });
+        });
+
+        StringBuilder searchWord = new StringBuilder();
+        for (String word : entityWords) {
+            searchWord.append(word);
+        }
+
+        EntityBlock entityBlock = new EntityBlock();
+        entityBlock.setEntityWords(entityWords);
+        entityBlock.setEntityTypes(entityTypes);
+        entityBlock.setPositions(positions);
+        entityBlock.setSearchWord(searchWord.toString());
+        entityBlock.setId(id);
+
+        return entityBlock;
+    }
+
+    /**
+     * 设置所有实体块对象
+     *
+     * @param entityGroups 实体组列表
+     * @return 实体块对象列表
+     */
+    private List<EntityBlock> setEntityBlocks(List<List<Lemma>> entityGroups) {
+
+        List<EntityBlock> entityBlocks = Lists.newArrayList();
+        for (int i = 0; i < entityGroups.size(); i++) {
+            entityBlocks.add(setEntityBlock(entityGroups.get(i), i));
+        }
+        return entityBlocks;
+    }
+
+    /**
+     * 生成倒排索引表
+     *
+     * @param entityBlocks 实体块对象列表
+     * @return {字符:实体块对象集合},倒排索引表
+     */
+    private Map<String, Set<EntityBlock>> generateInvertedIndexTable(List<EntityBlock> entityBlocks) {
+
+        Map<String, Map<Integer, EntityBlock>> invertedIndexTableTemp = Maps.newHashMap();  // 防止重复
+        entityBlocks.forEach(entityBlock -> {
+            String searchWord = entityBlock.getSearchWord();
+            for (int i = 0; i < searchWord.length(); i++) {
+                String char_ = searchWord.substring(i, i + 1);
+                Map<Integer, EntityBlock> idEntityBlockMap = invertedIndexTableTemp.getOrDefault(char_, Maps.newHashMap());
+                idEntityBlockMap.put(entityBlock.getId(), entityBlock);
+                invertedIndexTableTemp.put(char_, idEntityBlockMap);
+            }
+        });
+
+        Map<String, Set<EntityBlock>> invertedIndexTable = Maps.newHashMap();
+        invertedIndexTableTemp.forEach((char_, idEntityBlockMap) -> {
+            invertedIndexTable.put(char_, Sets.newHashSet(idEntityBlockMap.values()));
+        });
+
+        return invertedIndexTable;
+    }
+
+    /**
+     * 倒排索引生成流水线
+     * @return 倒排索引表
+     */
+    public Map<String, Set<EntityBlock>> generateInvertedIndexTablePipeline(){
+        filterEntitiesAndRelations();
+        List<List<Lemma>> entityGroups = mergeEntitiesByRelations();
+        List<EntityBlock> entityBlocks = setEntityBlocks(entityGroups);
+        return generateInvertedIndexTable(entityBlocks);
+    }
+
+}

+ 35 - 0
structure-center/src/main/java/com/lantone/structure/ai/model/Lemma.java

@@ -0,0 +1,35 @@
+package com.lantone.structure.ai.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @ClassName
+ * @Description 实体信息
+ * @Author fyeman
+ * @Date
+ * @Version 1.0
+ **/
+@Getter
+@Setter
+public class Lemma {
+    private int id;
+    private String text;
+    private String position;
+    private int from;
+    private int to;
+    private int len;
+    private String property;
+    private String relationName;
+    private Lemma parent;
+    private boolean haveChildren = false;
+    private List<Lemma> relationLemmas = new ArrayList<>();
+
+    public void addRelationLemmas(Lemma lemma) {
+        this.relationLemmas.add(lemma);
+        this.haveChildren = true;
+    }
+}

+ 19 - 0
structure-center/src/main/java/com/lantone/structure/ai/model/Relation.java

@@ -0,0 +1,19 @@
+package com.lantone.structure.ai.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : Relation
+ * @Description : 关系信息描述(基于AI)
+ * @Author : 楼辉荣
+ * @Date: 2020-03-11 10:46
+ */
+@Getter
+@Setter
+public class Relation {
+    private int id;
+    private int from;
+    private int to;
+    private String relationName;
+}

+ 394 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcess.java

@@ -0,0 +1,394 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.ai.model.Relation;
+import com.lantone.common.util.CatalogueUtil;
+import com.lantone.structure.model.entity.Negative;
+import com.lantone.structure.model.entity.PD;
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @Description:
+ * @Author: HUJING
+ * @Date: 2020/2/2 10:07
+ */
+@Component
+public class EntityProcess {
+    /**
+     * 树形结构存储三元组关系,返回传入实体类型为节点的所有关联实体对象
+     * @param aiOut
+     * @param entityType
+     * @return
+     */
+    public List<Lemma> createEntityTree(JSONObject aiOut, String entityType) {
+        List<Lemma> resultLemmaList = new ArrayList<>();
+        JSONObject annotation = aiOut.getJSONObject("annotation");
+        JSONArray entitys = annotation.getJSONArray("T");
+        JSONArray relations = annotation.getJSONArray("R");
+
+        if (entitys == null || entitys.isEmpty()) return resultLemmaList;
+
+        List<Lemma> allLemmaList = loadAllLemmaList(entitys);
+        for (Lemma l : allLemmaList) {
+            if (entityType.equals(l.getProperty())) {
+                List<String> relationIds = new ArrayList<>();
+                findRelationLemma(l, allLemmaList, relations, relationIds);
+                resultLemmaList.add(l);
+            }
+        }
+        return resultLemmaList;
+    }
+
+    /**
+     * 查找所有实体对象
+     * @param entitys
+     * @return
+     */
+    protected List<Lemma> loadAllLemmaList(JSONArray entitys) {
+        List<Lemma> allLemmaList = new ArrayList<>();
+        //所有实体读取
+        for (int i = 0; i < entitys.size(); i++) {
+            if (StringUtils.isEmpty(entitys.get(i).toString())) {
+                continue;
+            }
+            JSONObject entity = entitys.getJSONObject(i);
+            Lemma lemma = new Lemma();
+            lemma.setId(entity.getIntValue("id"));
+            lemma.setText(entity.getString("value"));
+            lemma.setProperty(entity.getString("name"));
+            lemma.setPosition(entity.getString("start"));
+            allLemmaList.add(lemma);
+        }
+        return allLemmaList;
+    }
+
+    /**
+     * 递归查询所有子实体信息
+     * @param lemma
+     * @param allLemmaList
+     * @param relations
+     */
+    private void findRelationLemma(Lemma lemma, List<Lemma> allLemmaList, JSONArray relations, List<String> relationIds) {
+        List<Relation> connectEntityIdList = getConnectEntityList(lemma.getId(), relations);
+        for (Lemma l : allLemmaList) {
+            for (Relation relation : connectEntityIdList) {
+                if (l.getId() == relation.getId()) {
+                    if (!hasRelation(l.getId(), lemma.getId(), relationIds)) {
+                        l.setRelationName(relation.getRelationName());
+
+                        List<Relation> childConnectEntityIdList = getConnectEntityList(l.getId(), relations);
+                        for (Lemma c_l : allLemmaList) {
+                            for (Relation c_relation : childConnectEntityIdList) {
+                                if (c_l.getId() == c_relation.getId()) {
+                                    if (!hasRelation(c_l.getId(), l.getId(), relationIds)) {
+                                        c_l.setRelationName(relation.getRelationName());
+                                        l.addRelationLemmas(c_l);
+                                    }
+                                }
+                            }
+                        }
+                        lemma.addRelationLemmas(l);
+//                        findRelationLemma(l, allLemmaList, relations, relationIds);
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean hasRelation(int a, int b, List<String> relationIds) {
+        String s = "";
+        if (a > b) {
+            s = a + "," + b;
+        } else {
+            s = b + "," + a;
+        }
+        if (relationIds.contains(s)) {
+            return true;
+        }
+        relationIds.add(s);
+        return false;
+    }
+
+    /**
+     * 处理关系抽取输出的json
+     *
+     * @param outputs    关系抽取输出的json
+     * @param entityType 需要处理的实体类别
+     * @return
+     */
+    public List<Map<String, String>> processJson(JSONObject outputs, String entityType) {
+        List<Map<String, String>> connectEntityList = new ArrayList<>();
+        Map<String, String> connectEntity = null;
+        JSONObject annotation = outputs.getJSONObject("annotation");
+        JSONArray entitys = annotation.getJSONArray("T");
+        JSONArray relations = annotation.getJSONArray("R");
+        for (int i = 0; i < entitys.size(); i++) {
+            if (StringUtils.isEmpty(entitys.get(i).toString())) {
+                continue;
+            }
+            JSONObject entity = entitys.getJSONObject(i);
+            if (entityType.equals(entity.getString("name"))) {
+                int id = entity.getIntValue("id");
+                List<Relation> connectEntityRelationList = getConnectEntityList(id, relations);
+                if (connectEntityRelationList.size() == 0) {
+                    connectEntity = new HashMap<>();
+                    connectEntity.put(entity.getString("name"), entity.getString("value"));
+                    connectEntityList.add(connectEntity);
+                } else {
+                    connectEntity = getConnectEntity(connectEntityRelationList, entitys);
+                    connectEntity.put(entity.getString("name"), entity.getString("value"));
+                    connectEntityList.add(connectEntity);
+                }
+            }
+        }
+        return connectEntityList;
+    }
+
+    /**
+     * 获取与传入实体有关系实体的id列表(List)
+     *
+     * @param entityId  传入实体的id
+     * @param relations 关系抽取出的关系对
+     * @return connectEntityIdList 有关系实体的id列表(List)
+     */
+    public List<Relation> getConnectEntityList(int entityId, JSONArray relations) {
+        List<Relation> connectEntityList = new ArrayList<>();
+        for (int i = 0; i < relations.size(); i++) {
+            if (StringUtils.isEmpty(relations.get(i).toString())) {
+                continue;
+            }
+            JSONObject relationObjs = relations.getJSONObject(i);
+            if (relationObjs.getIntValue("from") == entityId) {
+                Relation relation = new Relation();
+                relation.setId(relationObjs.getIntValue("to"));
+                relation.setFrom(relationObjs.getIntValue("from"));
+                relation.setTo(relationObjs.getIntValue("to"));
+                relation.setRelationName(relationObjs.getString("name"));
+                connectEntityList.add(relation);
+            }
+            if (relationObjs.getIntValue("to") == entityId) {
+                Relation relation = new Relation();
+                relation.setId(relationObjs.getIntValue("from"));
+                relation.setFrom(relationObjs.getIntValue("from"));
+                relation.setTo(relationObjs.getIntValue("to"));
+                relation.setRelationName(relationObjs.getString("name"));
+                connectEntityList.add(relation);
+            }
+        }
+        return connectEntityList;
+    }
+
+    /**
+     * 查找阴性表述, 阴性词需要在实体前面
+     * @param detailLemma
+     * @return
+     */
+    protected Negative findNegative(Lemma detailLemma) {
+        for (Lemma lemma : detailLemma.getRelationLemmas()) {
+            if (lemma.getProperty().equals(EntityEnum.NEGATIVE.toString())) {
+                if (StringUtils.isNotEmpty(lemma.getPosition()) && StringUtils.isNotEmpty(detailLemma.getPosition())) {
+                    if (Integer.parseInt(detailLemma.getPosition()) > Integer.parseInt(lemma.getPosition())) {
+                        Negative negative = new Negative();
+                        negative.setName(lemma.getText());
+                        return negative;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 查找时间表述
+     * @param detailLemma
+     * @return
+     */
+    protected PD findPD(Lemma detailLemma) {
+        for (Lemma lemma : detailLemma.getRelationLemmas()) {
+            if (lemma.getProperty().equals(EntityEnum.TIME.toString())) {
+                PD pd = new PD();
+                pd.setName(lemma.getText());
+                pd.setValue(lemma.getText());
+                return pd;
+            }
+        }
+        return null;
+    }
+
+    protected <T> T findT(Lemma detailLemma, T t, String entityType) throws Exception {
+        for (Lemma lemma : detailLemma.getRelationLemmas()) {
+            if (lemma.getProperty().equals(entityType)) {
+                BeanUtils.copyProperty(t, "name", lemma.getText());
+                return t;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 只找出现在lemma实体位置之后的实体
+     * @param detailLemma
+     * @param t
+     * @param entityType
+     * @param <T>
+     * @return
+     * @throws Exception
+     */
+    protected <T> T findTAfter(Lemma detailLemma, T t, String entityType) throws Exception {
+        for (Lemma lemma : detailLemma.getRelationLemmas()) {
+            if (lemma.getProperty().equals(entityType) && Integer.parseInt(detailLemma.getPosition()) < Integer.parseInt(lemma.getPosition())) {
+                BeanUtils.copyProperty(t, "name", lemma.getText());
+                return t;
+            }
+        }
+        return null;
+    }
+
+//    /**
+//     * 疾病名称需要映射操作
+//     * @param lemma
+//     * @param diag
+//     */
+//    protected void setDiag(Lemma lemma, Diag diag) {
+//        Map<String, String> diagRedisMap = (Map<String, String>)specialStorageUtil.get(KernelConstants.CONCEPT_DIAG_HOSPITAL_REFLECT);
+//        diag.setHospitalDiagName(lemma.getText());
+//        diag.setName(lemma.getText());//存放医院原始疾病名称
+//        diag.setName(diagRedisMap.get(lemma.getText()) == null ? "" : diagRedisMap.get(lemma.getText()));//映射到我们的标准疾病名称
+//    }
+
+    /**
+     * 查找时间
+     * @param detailLemma
+     * @return
+     */
+    protected List<PD> findTime(Lemma detailLemma) {
+        List<PD> timestamps = new ArrayList<>();
+        String value;
+        for (Lemma lemma : detailLemma.getRelationLemmas()) {
+            if (lemma.getProperty().equals(EntityEnum.TIME.toString())) {
+                PD pd = new PD();
+                value = lemma.getText();
+                String[] valUnit = new String[2];;
+                if (value.trim().length() > 0) {
+                    valUnit = CatalogueUtil.extractDigit(value);
+                }
+                pd.setValue(valUnit[0]);
+                pd.setUnit(valUnit[1]);
+                timestamps.add(pd);
+            }
+        }
+        return timestamps;
+    }
+
+    /**
+     * 获取实体id列表对应的所有实体类型及实体值
+     *
+     * @param connectEntityIdList 实体id列表
+     * @param entitys             关系抽取的实体列表
+     * @return entityRelationPair 实体id列表对应的所有实体类型及实体值
+     */
+    public Map<String, String> getConnectEntity(List<Relation> connectEntityIdList, JSONArray entitys) {
+        Map<String, String> entityRelationPair = new HashMap<>();
+        for (Relation connectEntityId : connectEntityIdList) {
+            for (int i = 0; i < entitys.size(); i++) {
+                if (StringUtils.isEmpty(entitys.get(i).toString())) {
+                    continue;
+                }
+                JSONObject entity = entitys.getJSONObject(i);
+                if (connectEntityId.getId() == entity.getIntValue("id")) {
+                    if (entityRelationPair.containsKey(entity.getString("name"))) {
+                        entityRelationPair.put(entity.getString("name"),
+                                entityRelationPair.get(entity.getString("name")) + "," + entity.getString("value"));
+                    } else {
+                        entityRelationPair.put(entity.getString("name"), entity.getString("value"));
+                    }
+                    break;
+                }
+            }
+        }
+        return entityRelationPair;
+    }
+
+    public  <T> List<T> addEntity(JSONObject aiOut, EntityEnum entityType, Class<T> t) throws Exception {
+        List<T> list = new ArrayList<>();
+        List<Map<String, String>> entityList = processJson(aiOut, entityType.toString());
+        for (Map<String, String> entityMap : entityList) {
+            if (StringUtils.isEmpty(entityMap.get(entityType.toString()))) {
+                continue;
+            }
+            T o = t.newInstance();
+            for (String key : entityMap.keySet()) {
+                if (key.equals(entityType.toString())) {
+                    BeanUtils.copyProperty(o, "name", entityMap.get(key));
+                } else if (key.equals(EntityEnum.NEGATIVE.toString())) {
+                    Negative negative = new Negative();
+                    negative.setName(StringUtils.isEmpty(entityMap.get(key)) ? "" : entityMap.get(key));
+                    BeanUtils.copyProperty(o, "negative", negative);
+                }
+            }
+            list.add(o);
+        }
+        return list;
+    }
+
+    protected  <T> List<T> addEntity(JSONObject aiOut, EntityEnum entityType, Class<T> t, EntityEnum[] subEntityTypes, Object[] subNames) throws Exception {
+        List<T> list = new ArrayList<>();
+        List<Map<String, String>> entityList = processJson(aiOut, entityType.toString());
+        for (Map<String, String> entityMap : entityList) {
+            if (StringUtils.isEmpty(entityMap.get(entityType.toString()))) {
+                continue;
+            }
+            T o = t.newInstance();
+            for (String key : entityMap.keySet()) {
+                if (key.equals(entityType.toString())) {
+                    BeanUtils.copyProperty(o, "name", entityMap.get(key));
+                } else {
+                    for (int i = 0; i < subEntityTypes.length; i++) {
+                        if (key.equals(subEntityTypes[i].toString())) {
+                            if (subNames[i] instanceof String) {
+                                BeanUtils.copyProperty(o, subNames[i].toString(), StringUtils.isEmpty(entityMap.get(key)) ? "" : entityMap.get(key));
+                            } else {
+                                BeanUtils.copyProperty(subNames[i], "name", StringUtils.isEmpty(entityMap.get(key)) ? "" : entityMap.get(key));
+                                BeanUtils.copyProperty(o, subNames[i].getClass().getSimpleName(), subNames[i]);
+                            }
+                        }
+                    }
+                }
+            }
+            list.add(o);
+        }
+        return list;
+    }
+
+
+    public String[] extract_digit(String value) {
+        String[] res = new String[2];
+        try {
+            String reg_time = "([\\d]+)([\\u4e00-\\u9fa5]+)";
+            Pattern pattern = Pattern.compile(reg_time);
+            Matcher matcher = pattern.matcher(value);
+            if (matcher.find(0)) {
+                res[0] = matcher.group(1);
+                res[1] = matcher.group(2);
+            } else {
+                res[0] = value;
+                res[1] = "";
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return res;
+    }
+}

+ 143 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessClinic.java

@@ -0,0 +1,143 @@
+package com.lantone.structure.ai.process;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.*;
+import com.lantone.structure.model.label.PresentLabel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 现病史处理
+ */
+public class EntityProcessClinic extends EntityProcess {
+    private Logger logger = LoggerFactory.getLogger(EntityProcessClinic.class);
+
+    public PresentLabel extractEntity(JSONObject aiOut) {
+        PresentLabel presentLabel = new PresentLabel();
+        try {
+            //临床表现
+            List<Lemma> clinicLemmas = createEntityTree(aiOut, EntityEnum.CLINICAL_FEATURE.toString());
+            for (Lemma lemma : clinicLemmas) {
+                Clinical clinical = new Clinical();
+                clinical.setName(lemma.getText());
+
+                List<PD> timestamp = new LinkedList<>();
+                for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                    if (relationLemma.getProperty().equals(EntityEnum.NEGATIVE.toString())) {
+                        clinical.setNegative(findNegative(lemma));
+                    }
+                    clinical.setModification(findT(lemma, new Modification(), EntityEnum.MODIFICATION.toString()));//修饰
+                    clinical.setBodyPart(findT(lemma, new BodyPart(), EntityEnum.BODY.toString()));//部位
+                    clinical.setTrend(findT(lemma, new Trend(), EntityEnum.TREND.toString()));//趋势
+                    clinical.setCause(findT(lemma, new Cause(), EntityEnum.CAUSE.toString()));//诱因
+                    clinical.setProperty(findT(lemma, new Property(), EntityEnum.PROPERTY.toString()));//性质
+                    clinical.setDegree(findT(lemma, new Degree(), EntityEnum.DEGREE.toString()));//程度
+                    clinical.setAggravate(findT(lemma, new Aggravate(), EntityEnum.AGGRAVATE.toString()));//加重因素
+                    clinical.setRelief(findT(lemma, new Relief(), EntityEnum.RELIEF.toString()));//缓解因素
+                    if (relationLemma.getProperty().equals(EntityEnum.TIME.toString())) {
+                        String[] time_split = relationLemma.getText().split(",");
+                        for (String time : time_split) {
+                            PD pd = new PD();
+                            String[] val_unit = new String[2];
+                            if (time.trim().length() > 0) {
+                                val_unit = extract_digit(time);
+                            }
+                            pd.setValue(val_unit[0]);
+                            pd.setUnit(val_unit[1]);
+                            pd.setName(time);
+                            timestamp.add(pd);
+                        }
+                    }
+                }
+                clinical.setTimestamp(timestamp);
+                presentLabel.add(presentLabel.getClinicals(), clinical);
+            }
+            //入院途径
+            List<Lemma> beHospitalizedWayLemmas = createEntityTree(aiOut, EntityEnum.BEHOSPITALIZEDWAY.toString());
+            for (Lemma lemma : beHospitalizedWayLemmas) {
+                BeHospitalizedWay beHospitalizedWay = new BeHospitalizedWay();
+                beHospitalizedWay.setName(lemma.getText());
+                presentLabel.setBeHospitalizedWay(beHospitalizedWay);
+            }
+            //诊断信息
+            EntityProcessDiag entityProcessDiag = new EntityProcessDiag();
+            List<Diag> diags = entityProcessDiag.extractEntity(aiOut);
+            presentLabel.setDiags(diags);
+
+            //一般情况信息
+            List<Lemma> geneLemmas = createEntityTree(aiOut, EntityEnum.GENERAL_DESCRIPT.toString());
+            for (Lemma lemma : geneLemmas) {
+                General general = new General();
+                general.setName(lemma.getText());
+                presentLabel.add(presentLabel.getGens(), general);
+            }
+            List<Lemma> causeLemmas = createEntityTree(aiOut, EntityEnum.CAUSE.toString());
+            List<Cause> causes = new ArrayList<>();
+            for (Lemma lemma : causeLemmas) {
+                Cause cause = new Cause();
+                cause.setName(lemma.getText());
+                causes.add(cause);
+            }
+            presentLabel.setCauses(causes);
+
+            //一般情况描述信息
+            EntityProcessGenerals entityProcessGeneral = new EntityProcessGenerals();
+            List<GeneralDesc> generals = entityProcessGeneral.extractEntity(aiOut);
+            presentLabel.setGenerals(generals);
+
+            //辅检信息
+            EntityProcessPacs entityProcessLis = new EntityProcessPacs();
+            List<Pacs> pacses = entityProcessLis.extractEntity(aiOut);
+            presentLabel.setPacses(pacses);
+
+            //治疗
+            List<Lemma> cureLemmas = createEntityTree(aiOut, EntityEnum.CURE.toString());
+            List<Treat> treats = new ArrayList<>();
+            for (Lemma lemma : cureLemmas) {
+                Treat treat = new Treat();
+                treat.setName(lemma.getText());
+                treats.add(treat);
+            }
+            presentLabel.setTreats(treats);
+            //治疗
+            List<Lemma> cureLemmas_me = createEntityTree(aiOut, EntityEnum.DRUG.toString());
+            List<Medicine> medicines = new ArrayList<>();
+            for (Lemma lemma : cureLemmas_me) {
+                Medicine medicine = new Medicine();
+                medicine.setName(lemma.getText());
+                medicines.add(medicine);
+            }
+            presentLabel.setMedicines(medicines);
+
+            //手术
+            List<Lemma> operationLemmas = createEntityTree(aiOut, EntityEnum.OPERATION.toString());
+            for (Lemma lemma : operationLemmas) {
+                Operation operation = new Operation();
+                operation.setName(lemma.getText());
+                presentLabel.add(presentLabel.getOperations(), operation);
+            }
+
+            //时间
+            List<Lemma> pdLemmas = createEntityTree(aiOut, EntityEnum.TIME.toString());
+            List<PD> pds = new ArrayList<>();
+            for (Lemma lemma : pdLemmas) {
+                PD pd = new PD();
+                pd.setName(lemma.getText());
+                pds.add(pd);
+            }
+            presentLabel.setPds(pds);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            logger.error(e.getMessage(), e);
+        }
+        return presentLabel;
+    }
+}

+ 39 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessDiag.java

@@ -0,0 +1,39 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.util.DiagEnhancer;
+import com.lantone.structure.model.entity.Diag;
+import com.lantone.structure.model.entity.PD;
+import com.lantone.structure.model.entity.Possible;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+public class EntityProcessDiag extends EntityProcess {
+    private Logger logger = LoggerFactory.getLogger(EntityProcessDiag.class);
+    public List<Diag> extractEntity(JSONObject aiOut) {
+        List<Diag> diags = new ArrayList<>();
+        try {
+            //读取疾病信息
+            List<Lemma> diagLemmas = createEntityTree(aiOut, EntityEnum.DIEASE.toString());
+            for (Lemma lemma : diagLemmas) {
+                Diag diag = DiagEnhancer.create(lemma.getText());
+                if (lemma.isHaveChildren()) {
+                    diag.setNegative(findNegative(lemma));//阴性
+                    diag.setPossible(findT(lemma, new Possible(), EntityEnum.POSSIBLE.toString()));//可能的
+                    diag.setPd(findT(lemma, new PD(), EntityEnum.TIME.toString()));//时间
+                }
+                diags.add(diag);
+            }
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        }
+        return diags;
+    }
+}

+ 89 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessDrug.java

@@ -0,0 +1,89 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.*;
+import org.apache.commons.beanutils.BeanUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+public class EntityProcessDrug extends EntityProcess {
+    private Logger logger = LoggerFactory.getLogger(EntityProcessDrug.class);
+
+    public List<Drug> extractEntity(JSONObject aiOut) {
+        String content = aiOut.getString("content");
+        //药物
+        List<Drug> drugs = new ArrayList<>();
+        try {
+            List<Lemma> drugLemmas = createEntityTree(aiOut, EntityEnum.DRUG.toString());
+            List<Lemma> consumptionLemmas = createEntityTree(aiOut, EntityEnum.CONSUMPTION.toString().split("-")[0]);
+            List<Lemma> usageWardRoundLemmas = createEntityTree(aiOut, EntityEnum.USAGE_WARD_ROUND.toString());
+            List<Lemma> frequencyLemmas = createEntityTree(aiOut, EntityEnum.FREQUENCY.toString());
+            List<Lemma> stopLemmas = createEntityTree(aiOut, EntityEnum.STOP.toString());
+            List<Lemma> reasonsForAntibioticLemmas = createEntityTree(aiOut, EntityEnum.REASONS_FOR_ANTIBIOTIC.toString());
+            for (Lemma lemma : drugLemmas) {
+                int lemmaPosition = Integer.parseInt(lemma.getPosition());
+                if (content.substring(Math.max(0, lemmaPosition - 10), lemmaPosition).contains("暂停")) {
+                    continue;
+                }
+                Drug drug = new Drug();
+                drug.setName(lemma.getText().replaceAll("[“”]",""));
+                drug.setConsumption(findTAfter(lemma, new Consumption(), EntityEnum.CONSUMPTION.toString().split("-")[0]));
+                drug.setUsageWardRound(findTAfter(lemma, new UsageWardRound(), EntityEnum.USAGE_WARD_ROUND.toString()));
+                drug.setFrequency(findTAfter(lemma, new Frequency(), EntityEnum.FREQUENCY.toString()));
+                drug.setStop(findTAfter(lemma, new Stop(), EntityEnum.STOP.toString()));
+                drug.setReasonsForAntibiotic(findTAfter(lemma, new ReasonsForAntibiotic(), EntityEnum.REASONS_FOR_ANTIBIOTIC.toString()));
+                //用量
+                if (drug.getConsumption() == null) {
+                    drug.setConsumption(setDrugs(consumptionLemmas, lemma, new Consumption()));
+                }
+                //用法
+                if (drug.getUsageWardRound() == null) {
+                    drug.setUsageWardRound(setDrugs(usageWardRoundLemmas, lemma, new UsageWardRound()));
+                }
+                //频率
+                if (drug.getFrequency() == null) {
+                    drug.setFrequency(setDrugs(frequencyLemmas, lemma, new Frequency()));
+                }
+                //停用
+                if (drug.getStop() == null) {
+                    drug.setStop(setDrugs(stopLemmas, lemma, new Stop()));
+                }
+                //抗生素使用原因
+                if (drug.getReasonsForAntibiotic() == null) {
+                    drug.setReasonsForAntibiotic(setDrugs(reasonsForAntibioticLemmas, lemma, new ReasonsForAntibiotic()));
+                }
+                drugs.add(drug);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            logger.error(e.getMessage(), e);
+        }
+        return drugs;
+    }
+
+    /**
+     * 模型抓取抗生素信息为空的时候判断是否在20个字节之内
+     *
+     * @param Lemmas
+     * @param lemma
+     * @param t
+     * @return
+     * @throws Exception
+     */
+    private <T> T setDrugs(List<Lemma> Lemmas, Lemma lemma, T t) throws Exception {
+        for (Lemma lem : Lemmas) {
+            if (Integer.parseInt(lem.getPosition()) - Integer.parseInt(lemma.getPosition()) <= 20) {
+                BeanUtils.copyProperty(t, "name", lemma.getText());
+                return t;
+            }
+        }
+        return null;
+    }
+}

+ 175 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessFamily.java

@@ -0,0 +1,175 @@
+package com.lantone.structure.ai.process;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.util.DiagEnhancer;
+import com.lantone.structure.model.entity.*;
+import com.lantone.structure.model.label.FamilyLabel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 家族史标签处理
+ */
+public class EntityProcessFamily extends EntityProcess {
+    private Logger logger = LoggerFactory.getLogger(EntityProcessFamily.class);
+
+    public FamilyLabel extractEntity(JSONObject aiOut) {
+        FamilyLabel familyLabel = new FamilyLabel();
+        List<Family> families = loadFamilies(aiOut);
+        familyLabel.setFamilies(families);
+        return familyLabel;
+    }
+
+    public List<Family> loadFamilies(JSONObject aiOut) {
+        //家属情况
+        List<Family> families = new ArrayList<>();
+        try {
+            //读取家属所有本体及关联信息
+            List<Lemma> familyLemmas = createEntityTree(aiOut, EntityEnum.RELATIVES.toString());
+            for (Lemma lemma : familyLemmas) {
+                Family family = new Family();
+                family.setName(lemma.getText());
+                if (lemma.isHaveChildren()) {
+                    for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                        if (relationLemma.getProperty().equals(EntityEnum.DEAD.toString())) {
+                            if (family.getDead() == null) {
+                                family.setDead(addDeadLemma(relationLemma));
+                            }
+                        } else if (relationLemma.getProperty().equals(EntityEnum.INFECTIOUS_KEYWORD.toString())) {
+                            family.setDiagInfectious(addInfectious(relationLemma));
+                        } else if (relationLemma.getProperty().equals(EntityEnum.GENETIC_DISEASE_KEYWORD.toString())) {
+                            family.setGeneticDiseaseKeyword(addGeneticDisease(relationLemma));
+                        } else if (relationLemma.getProperty().equals(EntityEnum.HEALTH.toString())) {
+                            family.setHealthCondition(addHealthCondition(relationLemma));
+                        } else if (relationLemma.getProperty().equals(EntityEnum.DIEASE.toString())) {
+                            family.addDiag(addDiags(relationLemma));
+                        } else if (relationLemma.getProperty().equals(EntityEnum.TUMOUR.toString())) {
+                            family.setTumour(findT(lemma, new Tumour(), EntityEnum.TUMOUR.toString()));//肿瘤病史
+                        }
+                    }
+                }
+                families.add(family);
+            }
+            List<Lemma> similarDiseaseLemmas = createEntityTree(aiOut, EntityEnum.SIMILAR_DISEASE_KEYWORD.toString());
+            for (Lemma relationLemma : similarDiseaseLemmas) {
+                Family family = new Family();
+                family.setSimilarDiag(addSimilarDiag(relationLemma));
+                families.add(family);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            logger.error(e.getMessage(), e);
+        }
+        return families;
+    }
+
+    /**
+     * 家属死亡
+     *
+     * @param deadLemma
+     * @return
+     */
+    private Dead addDeadLemma(Lemma deadLemma) {
+        Dead dead = new Dead();
+        dead.setName(deadLemma.getText());
+        if (deadLemma.isHaveChildren()) {
+            for (Lemma lemma : deadLemma.getRelationLemmas()) {
+                if (lemma.getProperty().equals(EntityEnum.DEAD_REASON.toString())) {
+                    DeadReason deadReason = new DeadReason();
+                    deadReason.setName(lemma.getText());
+                    dead.setDeadReason(deadReason);
+                } else if (lemma.getProperty().equals(EntityEnum.UNKNOWN.toString())) {
+                    Unknow unknow = new Unknow();
+                    unknow.setName(lemma.getText());
+                    dead.setUnknow(unknow);
+                } else if (lemma.getProperty().equals(EntityEnum.AGE.toString())) {
+                    Age age = new Age();
+                    age.setName(lemma.getText());
+                    dead.setAge(age);
+                } else if (lemma.getProperty().equals(EntityEnum.NEGATIVE.toString())) {
+                    Negative negative = new Negative();
+                    negative.setName(lemma.getText());
+                    dead.setNegative(negative);
+                }
+            }
+        }
+        return dead;
+    }
+
+    /**
+     * 家属传染病史
+     *
+     * @param infectiouLemma
+     * @return
+     */
+    private DiagInfectious addInfectious(Lemma infectiouLemma) {
+        DiagInfectious diagInfectious = new DiagInfectious();
+        diagInfectious.setName(infectiouLemma.getText());
+        if (infectiouLemma.isHaveChildren()) {
+            diagInfectious.setNegative(findNegative(infectiouLemma));
+        }
+        return diagInfectious;
+    }
+
+    /**
+     * 家属遗传病史
+     *
+     * @param geneticLemma
+     * @return
+     */
+    private GeneticDiseaseKeyword addGeneticDisease(Lemma geneticLemma) {
+        GeneticDiseaseKeyword geneticDiseaseKeyword = new GeneticDiseaseKeyword();
+        geneticDiseaseKeyword.setName(geneticLemma.getText());
+        if (geneticLemma.isHaveChildren()) {
+            geneticDiseaseKeyword.setNegative(findNegative(geneticLemma));
+        }
+        return geneticDiseaseKeyword;
+    }
+
+    /**
+     * 家属健康情况
+     *
+     * @param healthConditionLemma
+     * @return
+     */
+    private HealthCondition addHealthCondition(Lemma healthConditionLemma) {
+        HealthCondition healthCondition = new HealthCondition();
+        healthCondition.setName(healthConditionLemma.getText());
+        return healthCondition;
+    }
+
+    /**
+     * 家属疾病史
+     *
+     * @param diagLemma
+     * @return
+     */
+    private Diag addDiags(Lemma diagLemma) {
+        Diag diag = DiagEnhancer.create(diagLemma.getText());
+        if (diagLemma.isHaveChildren()) {
+            diag.setNegative(findNegative(diagLemma));
+        }
+        return diag;
+    }
+
+    /**
+     * 相似疾病
+     *
+     * @param diagLemma
+     * @return
+     */
+    private SimilarDiag addSimilarDiag(Lemma diagLemma) {
+        SimilarDiag similarDiag = new SimilarDiag();
+        similarDiag.setName(diagLemma.getText());
+        if (diagLemma.isHaveChildren()) {
+            similarDiag.setNegative(findNegative(diagLemma));
+        }
+        return similarDiag;
+    }
+}

+ 40 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessGenerals.java

@@ -0,0 +1,40 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.model.entity.GeneralDesc;
+import com.lantone.structure.model.entity.Negative;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class EntityProcessGenerals extends EntityProcess{
+    public List<GeneralDesc> extractEntity(JSONObject outputs) {
+        List<GeneralDesc> generals = new ArrayList<>();
+        GeneralDesc general;
+        List<Map<String, String>> generalEntityList = processJson(outputs, EntityEnum.GENERAL.toString());
+        for (Map<String, String> generalEntityMap : generalEntityList) {
+            if (StringUtils.isEmpty(generalEntityMap.get(EntityEnum.GENERAL.toString()))) {
+                continue;
+            }
+            general = new GeneralDesc();
+            for (String key : generalEntityMap.keySet()) {
+                String entity = StringUtils.isEmpty(generalEntityMap.get(key)) ? "" : generalEntityMap.get(key);
+                switch (EntityEnum.parseOfValue(key)){
+                    case GENERAL:
+                        general.setName(entity);
+                        break;
+                    case NEGATIVE:
+                        Negative negative = new Negative();
+                        negative.setName(entity);
+                        general.setNegative(negative);
+                        break;
+                }
+            }
+            generals.add(general);
+        }
+        return generals;
+    }
+}

+ 116 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessLeaveHospital.java

@@ -0,0 +1,116 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.BetterFinding;
+import com.lantone.structure.model.entity.Chief;
+import com.lantone.structure.model.entity.Diag;
+import com.lantone.structure.model.entity.DoctorAdvice;
+import com.lantone.structure.model.entity.Notes;
+import com.lantone.structure.model.entity.OutcomeCure;
+import com.lantone.structure.model.entity.OutcomeToBetter;
+import com.lantone.structure.model.entity.PositiveFinding;
+import com.lantone.structure.model.label.LeaveHospitalLabel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @ClassName : EntityProcessLeaveHospital
+ * @Description : 出院小结
+ * @Author : 胡敬
+ * @Date: 2020-03-20 11:20
+ */
+public class EntityProcessLeaveHospital extends EntityProcess {
+    public LeaveHospitalLabel extractEntity(JSONObject aiOut) {
+        LeaveHospitalLabel leaveHospitalLabel = new LeaveHospitalLabel();
+        //主诉
+        List<Lemma> chiefLemmas = createEntityTree(aiOut, EntityEnum.CHIEF.toString());
+        List<Chief> chiefs = new ArrayList<>();
+        for (Lemma lemma : chiefLemmas) {
+            Chief chief = new Chief();
+            chief.setName(lemma.getText());
+            chiefs.add(chief);
+        }
+        leaveHospitalLabel.setChiefs(chiefs);
+        //注意事项
+        List<Lemma> notesLemmas = createEntityTree(aiOut, EntityEnum.NOTES.toString());
+        List<Notes> noteses = new ArrayList<>();
+        for (Lemma lemma : notesLemmas) {
+            Notes notes = new Notes();
+            notes.setName(lemma.getText());
+            noteses.add(notes);
+        }
+        leaveHospitalLabel.setNoteses(noteses);
+        //出院诊断
+        List<Lemma> diagLemmas = createEntityTree(aiOut, EntityEnum.DIEASE.toString());
+        List<Diag> diags = new ArrayList<>();
+        for (Lemma lemma : diagLemmas) {
+            Diag diag = new Diag();
+            diag.setHospitalDiagName(lemma.getText());
+            diags.add(diag);
+        }
+        leaveHospitalLabel.setDiags(diags);
+        //医嘱
+        List<Lemma> keyWordForDoctorAdvicesesLemmas = createEntityTree(aiOut, EntityEnum.KEY_WORD_FOR_DOCTOR_ADVICES.toString());
+        List<Lemma> keyWordForPartLemmas = createEntityTree(aiOut, EntityEnum.KEY_WORD_FOR_PART.toString());
+        DoctorAdvice doctorAdvice = new DoctorAdvice();
+        int keyWordForDoctorAdvicesesStart = 0, partStart = 0, minPart = 0;
+        for (Lemma doctorAdviceLemma : keyWordForDoctorAdvicesesLemmas) {
+            keyWordForDoctorAdvicesesStart = Integer.parseInt(doctorAdviceLemma.getPosition());
+            for (Lemma part : keyWordForPartLemmas) {
+                partStart = Integer.parseInt(part.getPosition());
+                if (minPart == 0 || partStart > keyWordForDoctorAdvicesesStart && partStart < minPart) {
+                    minPart = partStart;
+                }
+            }
+        }
+        if (keyWordForDoctorAdvicesesStart < minPart) {
+            String content = aiOut.getString("content");
+            String doctorAdviceContent = content.substring(keyWordForDoctorAdvicesesStart, minPart);
+            doctorAdvice.setName(doctorAdviceContent);
+            leaveHospitalLabel.setDoctorAdvices(doctorAdvice);
+        }
+        //好转表现
+        List<Lemma> betterFindingLemmas = createEntityTree(aiOut, EntityEnum.BETTER_FINDING.toString());
+        List<BetterFinding> betterFindings = new ArrayList<>();
+        for (Lemma lemma : betterFindingLemmas) {
+            BetterFinding betterFinding = new BetterFinding();
+            betterFinding.setName(lemma.getText());
+            betterFindings.add(betterFinding);
+        }
+        leaveHospitalLabel.setBetterFindings(betterFindings);
+
+        //转归情况-好转
+        List<Lemma> outcomeToBetterLemmas = createEntityTree(aiOut, EntityEnum.OUTCOME_TO_BETTER.toString());
+        List<OutcomeToBetter> outcomeToBetters = new ArrayList<>();
+        for (Lemma lemma : outcomeToBetterLemmas) {
+            OutcomeToBetter outcomeToBetter = new OutcomeToBetter();
+            outcomeToBetter.setName(lemma.getText());
+            outcomeToBetters.add(outcomeToBetter);
+        }
+        leaveHospitalLabel.setOutcomeToBetters(outcomeToBetters);
+
+        //转归情况-治愈
+        List<Lemma> outcomeCureLemmas = createEntityTree(aiOut, EntityEnum.OUTCOME_CURE.toString());
+        List<OutcomeCure> outcomeCures = new ArrayList<>();
+        for (Lemma lemma : outcomeCureLemmas) {
+            OutcomeCure outcomeCure = new OutcomeCure();
+            outcomeCure.setName(lemma.getText());
+            outcomeCures.add(outcomeCure);
+        }
+        leaveHospitalLabel.setOutcomeCures(outcomeCures);
+
+        //阳性表现
+        List<Lemma> positiveFindingLemmas = createEntityTree(aiOut, EntityEnum.POSITIVE_FINDING.toString());
+        List<PositiveFinding> positiveFindings = new ArrayList<>();
+        for (Lemma lemma : positiveFindingLemmas) {
+            PositiveFinding positiveFinding = new PositiveFinding();
+            positiveFinding.setName(lemma.getText());
+            positiveFindings.add(positiveFinding);
+        }
+        leaveHospitalLabel.setPositiveFindings(positiveFindings);
+        return leaveHospitalLabel;
+    }
+}

+ 50 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessLis.java

@@ -0,0 +1,50 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.model.entity.Lis;
+import com.lantone.structure.model.entity.LisValue;
+import com.lantone.structure.model.entity.PD;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class EntityProcessLis extends EntityProcess {
+    public List<Lis> extractEntity(JSONObject outputs) {
+        List<Lis> lises = new ArrayList<>();
+        Lis lis = null;
+        List<Map<String, String>> lisEntityList = processJson(outputs, EntityEnum.LABORATORY.toString());
+        for (Map<String, String> lisEntityMap : lisEntityList) {
+            if (StringUtils.isEmpty(lisEntityMap.get(EntityEnum.LABORATORY.toString()))) {
+                continue;
+            }
+            lis = new Lis();
+            for (String key : lisEntityMap.keySet()) {
+                String entity = StringUtils.isEmpty(lisEntityMap.get(key)) ? "" : lisEntityMap.get(key);
+                switch (EntityEnum.parseOfValue(key)) {
+                    case LABORATORY:
+                        lis.setName(entity);
+                        break;
+                    case LABORATORY_VALUE:
+                        LisValue lisValue = new LisValue();
+                        lisValue.setName(entity);
+                        lis.setLisValue(lisValue);
+                        PD pd = new PD();
+                        String value = entity;
+                        String[] val_unit = new String[2];
+                        if (value.trim().length() > 0) {
+                            val_unit = extract_digit(value);
+                        }
+                        pd.setValue(val_unit[0]);
+                        pd.setUnit(val_unit[1]);
+                        lis.setPd(pd);
+                        break;
+                }
+            }
+            lises.add(lis);
+        }
+        return lises;
+    }
+}

+ 70 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessMarital.java

@@ -0,0 +1,70 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.*;
+import com.lantone.structure.model.label.MaritalLabel;
+
+import java.util.List;
+
+/**
+ * @ClassName : EntityProcessMarital
+ * @Description : 婚育史
+ * @Author : 楼辉荣
+ * @Date: 2020-03-10 10:20
+ */
+public class EntityProcessMarital extends EntityProcess {
+    public MaritalLabel extractEntity(JSONObject aiOut) {
+        MaritalLabel maritalLabel = new MaritalLabel();
+        //家属情况
+        EntityProcessFamily entityProcessFamily = new EntityProcessFamily();
+        maritalLabel.setFamily(entityProcessFamily.extractEntity(aiOut).getFamilies());
+        //读取近亲史所有本体及关联信息
+        List<Lemma> consanguineousLemmas = createEntityTree(aiOut, EntityEnum.NEAR_RELATION.toString());
+        for (Lemma lemma :consanguineousLemmas) {
+            Consanguineous consanguineous = new Consanguineous();
+            consanguineous.setName(lemma.getText());
+            if (lemma.isHaveChildren()) {
+                consanguineous.setNegative(findNegative(lemma));
+            }
+            maritalLabel.setConsanguineous(consanguineous);
+        }
+        //读取结婚年龄所有本体及关联信息
+        List<Lemma> marryiageLemmas = createEntityTree(aiOut, EntityEnum.MARRYIAGE.toString());
+        for (Lemma lemma :marryiageLemmas) {
+            Marryiage marryiage = new Marryiage();
+            marryiage.setName(lemma.getText());
+            maritalLabel.setMarryiage(marryiage);
+        }
+        //读取结婚年龄所有本体及关联信息
+        List<Lemma> ageLemmas = createEntityTree(aiOut, EntityEnum.AGE.toString());
+        for (Lemma lemma :ageLemmas) {
+            Marryiage marryiage = new Marryiage();
+            marryiage.setName(lemma.getText());
+            maritalLabel.setMarryiage(marryiage);
+        }
+        //婚姻情况描述
+        List<Lemma> maritalStatusLemmas = createEntityTree(aiOut, EntityEnum.MARITAL_STATUS.toString());
+        for (Lemma lemma :maritalStatusLemmas) {
+            MaritalStatus maritalStatus = new MaritalStatus();
+            maritalStatus.setName(lemma.getText());
+            maritalLabel.setMaritalStatus(maritalStatus);
+        }
+        //夫妻关系描述
+        List<Lemma> conjugalRelationLemmas = createEntityTree(aiOut, EntityEnum.CONJUGAL_RELATION.toString());
+        for (Lemma lemma :conjugalRelationLemmas) {
+            ConjugalRelation conjugalRelation = new ConjugalRelation();
+            conjugalRelation.setName(lemma.getText());
+            maritalLabel.setConjugalRelation(conjugalRelation);
+        }
+        //生育情况描述
+        List<Lemma> fertilityLemmas = createEntityTree(aiOut, EntityEnum.BIRTH_HIS.toString());
+        for (Lemma lemma :fertilityLemmas) {
+            Fertility fertility = new Fertility();
+            fertility.setName(lemma.getText());
+            maritalLabel.setFertility(fertility);
+        }
+        return maritalLabel;
+    }
+}

+ 127 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessMenses.java

@@ -0,0 +1,127 @@
+package com.lantone.structure.ai.process;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.Clinical;
+import com.lantone.structure.model.entity.LastMenstrual;
+import com.lantone.structure.model.entity.Leukorrhea;
+import com.lantone.structure.model.entity.MenarcheAge;
+import com.lantone.structure.model.entity.MenopauseAge;
+import com.lantone.structure.model.entity.MenopauseTime;
+import com.lantone.structure.model.entity.Menses;
+import com.lantone.structure.model.entity.MensesDuration;
+import com.lantone.structure.model.entity.MenstrualCycle;
+import com.lantone.structure.model.label.MenstrualLabel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 月经史标签处理
+ */
+public class EntityProcessMenses extends EntityProcess {
+
+    public MenstrualLabel extractEntity(JSONObject aiOut) {
+        MenstrualLabel menstrualLabel = new MenstrualLabel();
+        //月经情况
+        List<Menses> mensesList = new ArrayList<>();
+        //读取月经所有本体及关联信息
+        List<Lemma> mensesLemmas = createEntityTree(aiOut, EntityEnum.MENSES.toString());
+        List<Clinical> clinicals;
+        for (Lemma lemma : mensesLemmas) {
+            Menses menses = new Menses();
+            clinicals = new ArrayList<>();
+            menses.setName(lemma.getText());
+            if (lemma.isHaveChildren()) {
+                for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                    if (relationLemma.getProperty().equals(EntityEnum.CLINICAL_FEATURE.toString())) {
+                        addClinicalLemma(clinicals, relationLemma);
+                    } else if (relationLemma.getProperty().equals(EntityEnum.AGE.toString())) {
+                        findMensesAge(menses, relationLemma);
+                    } else if (relationLemma.getProperty().equals(EntityEnum.TIME.toString())) {
+                        findMensesTime(menses, relationLemma);
+                    }
+                }
+                menses.setClinicals(clinicals);
+            }
+            mensesList.add(menses);
+        }
+        menstrualLabel.setMensesList(mensesList);
+        //白带情况
+        List<Leukorrhea> leukorrheas = new ArrayList<>();
+        //读取月经所有本体及关联信息
+        List<Lemma> leukorrheaLemmas = createEntityTree(aiOut, EntityEnum.LEUKORRHEA.toString());
+        for (Lemma lemma : leukorrheaLemmas) {
+            Leukorrhea leukorrhea = new Leukorrhea();
+            clinicals = new ArrayList<>();
+            leukorrhea.setName(lemma.getText());
+            if (lemma.isHaveChildren()) {
+                for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                    if (relationLemma.getProperty().equals(EntityEnum.CLINICAL_FEATURE.toString())) {
+                        addClinicalLemma(clinicals, relationLemma);
+                    }
+                }
+                leukorrhea.setClinical(clinicals);
+            }
+            leukorrheas.add(leukorrhea);
+        }
+        menstrualLabel.setLeukorrheas(leukorrheas);
+        return menstrualLabel;
+    }
+
+    /**
+     * 查找临床表现
+     *
+     * @param clinicals
+     * @param clinicalLemma
+     */
+    private void addClinicalLemma(List<Clinical> clinicals, Lemma clinicalLemma) {
+        Clinical clinical = new Clinical();
+        clinical.setName(clinicalLemma.getText());
+        if (clinicalLemma.isHaveChildren()) {
+            clinical.setTimestamp(findTime(clinicalLemma));
+            clinical.setNegative(findNegative(clinicalLemma));
+        }
+        clinicals.add(clinical);
+    }
+
+    /**
+     * 查找初潮年龄
+     *
+     * @param detailLemma
+     * @return
+     */
+    private void findMensesAge(Menses menses, Lemma detailLemma) {
+        if (detailLemma.getRelationName().contains("初潮")) {
+            MenarcheAge menarcheAge = new MenarcheAge();
+            menarcheAge.setName(detailLemma.getText());
+            menses.setMenarcheAge(menarcheAge);
+        } else if (detailLemma.getRelationName().contains("绝经")) {
+            MenopauseAge menopauseAge = new MenopauseAge();
+            menopauseAge.setName(detailLemma.getText());
+            menses.setMenopauseAge(menopauseAge);
+        }
+    }
+
+    private void findMensesTime(Menses menses, Lemma detailLemma) {
+        if (detailLemma.getRelationName().contains("行经天数")) {
+            MensesDuration mensesDuration = new MensesDuration();
+            mensesDuration.setName(detailLemma.getText());
+            menses.setMensesDuration(mensesDuration);
+        } else if (detailLemma.getRelationName().contains("月经周期")) {
+            MenstrualCycle menstrualCycle = new MenstrualCycle();
+            menstrualCycle.setName(detailLemma.getText());
+            menses.setMenstrualCycle(menstrualCycle);
+        } else if (detailLemma.getRelationName().contains("末次月经")) {
+            LastMenstrual lastMenstrual = new LastMenstrual();
+            lastMenstrual.setName(detailLemma.getText());
+            menses.setLastMenstrual(lastMenstrual);
+        } else if (detailLemma.getRelationName().contains("绝经")) {
+            MenopauseTime menopauseTime = new MenopauseTime();
+            menopauseTime.setName(detailLemma.getText());
+            menses.setMenopauseTime(menopauseTime);
+        }
+    }
+}

+ 140 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessOperationDiscussion.java

@@ -0,0 +1,140 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.Vital;
+import com.lantone.structure.model.label.OperationDiscussionLabel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : EntityProcessOperationDiscussion
+ * @Description : 术后首次病程及谈话记录
+ * @Author : 胡敬
+ * @Date: 2020-03-24 10:48
+ */
+public class EntityProcessOperationDiscussion extends EntityProcess {
+    private List<String> titleList = Arrays.asList(
+            EntityEnum.TITLE.toString(),
+            EntityEnum.TITLE_OF_OPERATIVE_FINDINGS.toString(),
+            EntityEnum.TITLE_OF_MEASURES_AFTER_OP.toString(),
+            EntityEnum.TITLE_OF_RISK_AFTER_OP.toString(),
+            EntityEnum.TITLE_OF_ATTENTION_AFTER_OP.toString());
+
+    public OperationDiscussionLabel extractEntity(JSONObject aiOut) {
+        OperationDiscussionLabel operationDiscussionLabel = new OperationDiscussionLabel();
+        String content = aiOut.getString("content");
+
+        Map<String, List<String>> titleText = subWithTitle(aiOut);
+        //手术经过文本(术中所见)
+        if (titleText.get(EntityEnum.TITLE_OF_OPERATIVE_FINDINGS.toString()) != null) {
+            List<String> operativeFindingsList = titleText.get(EntityEnum.TITLE_OF_OPERATIVE_FINDINGS.toString());
+            String text = textJoin(content, operativeFindingsList);
+            operationDiscussionLabel.setOperativeFindings(text);
+        }
+
+        //术后风险文本
+        if (titleText.get(EntityEnum.TITLE_OF_RISK_AFTER_OP.toString()) != null) {
+            List<String> riskAfterOpList = titleText.get(EntityEnum.TITLE_OF_RISK_AFTER_OP.toString());
+            String text = textJoin(content, riskAfterOpList);
+            operationDiscussionLabel.setRiskAfterOp(text);
+        }
+
+        //术后注意事项文本(处理及注意事项)
+        if (titleText.get(EntityEnum.TITLE_OF_ATTENTION_AFTER_OP.toString()) != null) {
+            List<String> attentionAfterOpList = titleText.get(EntityEnum.TITLE_OF_ATTENTION_AFTER_OP.toString());
+            String text = textJoin(content, attentionAfterOpList);
+            operationDiscussionLabel.setAttentionAfterOp(text);
+        }
+
+        //术后处理措施文本(处理及注意事项)
+        if (titleText.get(EntityEnum.TITLE_OF_MEASURES_AFTER_OP.toString()) != null) {
+            List<String> measuresAfterOpList = titleText.get(EntityEnum.TITLE_OF_MEASURES_AFTER_OP.toString());
+            String text = textJoin(content, measuresAfterOpList);
+            operationDiscussionLabel.setMeasuresAfterOp(text);
+        }
+
+        //生命体征
+        List<Lemma> vitalLemmas = createEntityTree(aiOut, EntityEnum.VITAL.toString());
+        List<Vital> vitals = new ArrayList<>();
+        for (Lemma lemma : vitalLemmas) {
+            Vital vital = new Vital();
+            vital.setValue(lemma.getText());
+            vitals.add(vital);
+        }
+        operationDiscussionLabel.setVitals(vitals);
+        return operationDiscussionLabel;
+    }
+
+    private String textJoin(String content, List<String> operativeFindingsList) {
+        StringBuffer text = new StringBuffer();
+        for (String titleTextIndex : operativeFindingsList) {
+            String[] titleTextIndexSplit = titleTextIndex.split(",");
+            text.append(content.substring(Integer.parseInt(titleTextIndexSplit[0]),
+                    Integer.parseInt(titleTextIndexSplit[1])));
+        }
+        return text.toString();
+    }
+
+    /**
+     * 根据各标题截取文本index
+     *
+     * @param aiOut
+     * @return
+     */
+    private Map<String, List<String>> subWithTitle(JSONObject aiOut) {
+        Map<String, List<String>> titleText = new LinkedHashMap<>();
+        String content = aiOut.getString("content");
+        List<Lemma> lemmaList = loadAllLemmaList(aiOut.getJSONObject("annotation").getJSONArray("T"));
+        Lemma lemma;
+        int start = 0;
+        String subContentIndex = "", title = "";
+        for (int i = 0; i < lemmaList.size(); i++) {
+            lemma = lemmaList.get(i);
+            if (!titleList.contains(lemma.getProperty()) && i != lemmaList.size() - 1) {
+                continue;
+            }
+            if (i != lemmaList.size() - 1) {
+                if (start == 0) {
+                    start = Integer.parseInt(lemma.getPosition());
+                    title = lemma.getProperty();//截取的这一段文本的标题
+                } else {
+                    /*subContentIndex = start + lemma.getText().length() + 1 + "," + Integer.parseInt(lemma.getPosition());*/
+                    subContentIndex = start + "," + Integer.parseInt(lemma.getPosition());
+                    putSubContent(titleText, title, subContentIndex);
+                    start = Integer.parseInt(lemma.getPosition());
+                    title = lemma.getProperty();//截取的这一段文本的标题
+                }
+            } else {
+                //将倒数第二个标题存入结构
+                subContentIndex = start + "," + Integer.parseInt(lemma.getPosition());
+                putSubContent(titleText, title, subContentIndex);
+                //如果是最后一个Lemma,文本就从当前lemma的position开始取,取到结束
+                title = lemma.getProperty();//截取的这一段文本的标题
+                if (titleList.contains(title)) {
+                    start = Integer.parseInt(lemma.getPosition());
+                    int lastIndex = content.length() - 1;
+                    subContentIndex = start + "," + lastIndex;
+                    putSubContent(titleText, title, subContentIndex);
+                }
+            }
+        }
+        return titleText;
+    }
+
+    private void putSubContent(Map<String, List<String>> titleText, String text, String subContent) {
+        List<String> textList;
+        if (titleText.containsKey(text)) {
+            titleText.get(text).add(subContent);
+        } else {
+            textList = new ArrayList<>();
+            textList.add(subContent);
+            titleText.put(text, textList);
+        }
+    }
+}

+ 120 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessPacs.java

@@ -0,0 +1,120 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.util.DiagEnhancer;
+import com.lantone.structure.model.entity.BodyPart;
+import com.lantone.structure.model.entity.Diag;
+import com.lantone.structure.model.entity.OuterCourtyard;
+import com.lantone.structure.model.entity.PD;
+import com.lantone.structure.model.entity.Pacs;
+import com.lantone.structure.model.entity.PacsValue;
+import com.lantone.structure.model.entity.Possible;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityProcessPacs extends EntityProcess {
+    private Logger logger = LoggerFactory.getLogger(EntityProcessPacs.class);
+
+    public List<Pacs> extractEntity(JSONObject aiOut) {
+        //辅检情况
+        List<Pacs> pacses = new ArrayList<>();
+        List<Lemma> pacsLemmas = createEntityTree(aiOut, EntityEnum.AUXILIARY_EXAMINATION.toString());
+        for (Lemma lemma : pacsLemmas) {
+            Pacs pacs = new Pacs();
+            pacs.setName(lemma.getText());
+            if (lemma.isHaveChildren()) {
+                for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                    if (relationLemma.getProperty().equals(EntityEnum.AUXILIARY_DESCRIPT.toString())) {
+                        pacs.setPacsValues(addPacsValue(relationLemma));
+                    } else if (relationLemma.getProperty().equals(EntityEnum.BODY.toString())) {
+                        pacs.setBodyPart(addBodyPart(relationLemma));
+                    } else if (relationLemma.getProperty().equals(EntityEnum.OUTERCOURTYARD.toString())) {
+                        pacs.setOuterCourtyard(addOuterCourtyard(relationLemma));
+                    }
+                }
+            }
+            pacses.add(pacs);
+        }
+        //辅检提取疾病
+        List<Diag> diags = new ArrayList<>();
+        try {
+            //读取疾病信息
+            List<Lemma> diagLemmas = createEntityTree(aiOut, EntityEnum.DIEASE.toString());
+            for (Lemma lemma : diagLemmas) {
+                Diag diag = DiagEnhancer.create(lemma.getText());
+                if (lemma.isHaveChildren()) {
+                    diag.setNegative(findNegative(lemma));//阴性
+                    diag.setPossible(findT(lemma, new Possible(), EntityEnum.POSSIBLE.toString()));//可能的
+                    diag.setPd(findT(lemma, new PD(), EntityEnum.TIME.toString()));//时间
+                }
+                diags.add(diag);
+            }
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        }
+        Pacs pacs = new Pacs();
+        pacs.setDiags(diags);
+        pacses.add(pacs);
+        //辅检时间(不是辅检具体项目时间)
+        List<Lemma> pdLemmas = createEntityTree(aiOut, EntityEnum.TIME.toString());
+        for (Lemma lemma : pdLemmas) {
+            PD pd = new PD();
+            pd.setName(lemma.getText());
+            pacs = new Pacs();
+            pacs.setPd(pd);
+            pacses.add(pacs);
+        }
+        return pacses;
+    }
+
+    /**
+     * 添加辅助检查描述
+     *
+     * @param relationLemma
+     * @return
+     */
+    private PacsValue addPacsValue(Lemma relationLemma) {
+        PacsValue pacsValue = new PacsValue();
+        pacsValue.setName(relationLemma.getText());
+        return pacsValue;
+    }
+
+    /**
+     * 添加身体部位
+     *
+     * @param relationLemma
+     * @return
+     */
+    private BodyPart addBodyPart(Lemma relationLemma) {
+        BodyPart bodyPart = new BodyPart();
+        bodyPart.setName(relationLemma.getText());
+        return bodyPart;
+    }
+
+    /**
+     * 添加外院
+     *
+     * @param relationLemma
+     * @return
+     */
+    private OuterCourtyard addOuterCourtyard(Lemma relationLemma) {
+        OuterCourtyard outerCourtyard = new OuterCourtyard();
+        outerCourtyard.setName(relationLemma.getText());
+        if (relationLemma.isHaveChildren()) {
+            outerCourtyard.setPd(findTime(relationLemma));
+            for (Lemma lemma : relationLemma.getRelationLemmas()) {
+                if (lemma.getProperty().equals(EntityEnum.AUXILIARY_DESCRIPT.toString())) {
+                    outerCourtyard.setPacsValue(addPacsValue(lemma));
+                    break;
+                }
+            }
+        }
+        return outerCourtyard;
+    }
+
+}

+ 198 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessPast.java

@@ -0,0 +1,198 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.util.DiagEnhancer;
+import com.lantone.structure.model.entity.*;
+import com.lantone.structure.model.label.PastLabel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @ClassName : EntityProcessPast
+ * @Description : 既往史
+ * @Author : 楼辉荣
+ * @Date: 2020-03-10 10:20
+ */
+@Component
+public class EntityProcessPast extends EntityProcess {
+    private Logger logger = LoggerFactory.getLogger(EntityProcessPast.class);
+
+    public PastLabel extractEntity(JSONObject aiOut) {
+        PastLabel pastLabel = new PastLabel();
+        try {
+            //读取疾病信息
+            List<Lemma> diagLemmas = createEntityTree(aiOut, EntityEnum.DIEASE.toString());
+            for (Lemma lemma : diagLemmas) {
+                Diag diag = DiagEnhancer.create(lemma.getText());
+                if (lemma.isHaveChildren()) {
+                    //阴性
+                    diag.setNegative(findNegative(lemma));
+                    //可能的
+                    for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                        if (relationLemma.getProperty().equals(EntityEnum.POSSIBLE.toString())) {
+                            Possible possible = new Possible();
+                            possible.setName(relationLemma.getText());
+                            diag.setPossible(possible);
+                        }
+                    }
+                }
+                pastLabel.addDiag(diag);
+            }
+            //手术名称
+            List<Lemma> operationLemmas = createEntityTree(aiOut, EntityEnum.OPERATION.toString());
+            for (Lemma lemma : operationLemmas) {
+                Operation operation = new Operation();
+                operation.setName(lemma.getText().replaceAll("[“”]",""));
+                if (lemma.isHaveChildren()) {
+                    //阴性
+                    operation.setNegative(findNegative(lemma));
+                    //时间
+                    operation.setPd(findPD(lemma));
+                    //手术结果
+                    for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                        if (relationLemma.getProperty().equals(EntityEnum.OPERATION_RESULT.toString())) {
+                            OperationResult operationResult = new OperationResult();
+                            operationResult.setName(relationLemma.getText());
+                            operation.setOperationResult(operationResult);
+                        }
+                    }
+                    //手术原因
+                    for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                        if (relationLemma.getProperty().equals(EntityEnum.DIEASE.toString())) {
+                            Diag diag = DiagEnhancer.create(relationLemma.getText());
+                            operation.setDiag(diag);
+                        }
+                    }
+                }
+                pastLabel.addOperation(operation);
+            }
+            //手术史
+            List<Lemma> operationHistoryLemmas = createEntityTree(aiOut, EntityEnum.OPERATION_KEYWORD.toString());
+            for (Lemma lemma : operationHistoryLemmas) {
+                Operation operation = new Operation();
+                operation.setName(lemma.getText().replaceAll("[“”]",""));
+                if (lemma.isHaveChildren()) {
+                    operation.setNegative(findNegative(lemma));//阴性
+                }
+                pastLabel.addOperation(operation);
+            }
+
+            //外伤史
+            List<Lemma> woundLemmas = createEntityTree(aiOut, EntityEnum.INJURY.toString());
+            for (Lemma lemma : woundLemmas) {
+                Wound wound = new Wound();
+                wound.setName(lemma.getText());
+                if (lemma.isHaveChildren()) {
+                    wound.setNegative(findNegative(lemma));//阴性
+                    wound.setPd(findPD(lemma));//时间
+                    wound.setBodyPart(findT(lemma, new BodyPart(), EntityEnum.BODY.toString()));//部位
+                    wound.setDegree(findT(lemma, new Degree(), EntityEnum.TREND.toString()));//程度
+                    wound.setTreat(findT(lemma, new Treat(), EntityEnum.CURE.toString()));//治疗
+                    wound.setOperation(findT(lemma, new Operation(), EntityEnum.OPERATION.toString()));//手术
+                }
+                pastLabel.addWound(wound);
+            }
+            //过敏史
+            List<Lemma> allergyLemmas = createEntityTree(aiOut, EntityEnum.ALLERGY.toString());
+            for (Lemma lemma : allergyLemmas) {
+                Allergy allergy = new Allergy();
+                allergy.setName(lemma.getText());
+                allergy.setNegative(findNegative(lemma));
+                for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                    //食物过敏史
+                    if (relationLemma.getProperty().equals(EntityEnum.FOOD_ALLERGY.toString())) {
+                        AllergyFood allergyFood = new AllergyFood();
+                        allergyFood.setName(relationLemma.getText());
+                        allergyFood.setNegative(findNegative(relationLemma));//阴性
+                        allergyFood.setPd(findPD(relationLemma));//时间
+                        allergyFood.setDegree(findT(relationLemma, new Degree(), EntityEnum.TREND.toString()));//程度
+                        allergyFood.setAllergyDesc(findT(relationLemma, new AllergyDesc(), EntityEnum.ALLERGY_SYMPTOM.toString()));//过敏表现
+                        allergy.setAllergyFood(allergyFood);
+                    }
+                    //药物过敏史
+                    if (relationLemma.getProperty().equals(EntityEnum.DRUG_ALLERGY.toString())) {
+                        AllergyMedicine allergyMedicine = new AllergyMedicine();
+                        allergyMedicine.setName(relationLemma.getText());
+                        allergyMedicine.setNegative(findNegative(relationLemma));//阴性
+                        allergyMedicine.setPd(findPD(relationLemma));//时间
+                        allergyMedicine.setDegree(findT(relationLemma, new Degree(), EntityEnum.TREND.toString()));//程度
+                        allergyMedicine.setAllergyDesc(findT(relationLemma, new AllergyDesc(), EntityEnum.ALLERGY_SYMPTOM.toString()));//过敏表现
+                        allergy.setAllergyMedicine(allergyMedicine);
+                    }
+                }
+                pastLabel.addAllergy(allergy);
+            }
+//            //食物过敏史
+//            List<Lemma> allergyFoodLemmas = createEntityTree(aiOut, EntityEnum.FOOD_ALLERGY.toString());
+//            for (Lemma lemma : allergyFoodLemmas) {
+//                AllergyFood allergyFood = new AllergyFood();
+//                allergyFood.setName(lemma.getText());
+//                if (lemma.isHaveChildren()) {
+//                    allergyFood.setNegative(findNegative(lemma));
+//                    allergyFood.setPd(findPD(lemma));//时间
+//                    allergyFood.setDegree(findT(lemma, new Degree(), EntityEnum.TREND.toString()));//程度
+//                }
+//                pastLabel.addAllergyFood(allergyFood);
+//            }
+//            //药物过敏史
+//            List<Lemma> allergyMedicineLemmas = createEntityTree(aiOut, EntityEnum.DRUG_ALLERGY.toString());
+//            for (Lemma lemma : allergyMedicineLemmas) {
+//                AllergyMedicine allergyMedicine = new AllergyMedicine();
+//                allergyMedicine.setName(lemma.getText());
+//                if (lemma.isHaveChildren()) {
+//                    allergyMedicine.setNegative(findNegative(lemma));
+//                    allergyMedicine.setPd(findPD(lemma));//时间
+//                    allergyMedicine.setDegree(findT(lemma, new Degree(), EntityEnum.TREND.toString()));//程度
+//                }
+//                pastLabel.addAllergyMedicine(allergyMedicine);
+//            }
+            //输血史
+            List<Lemma> bloodTransfusionLemmas = createEntityTree(aiOut, EntityEnum.BLOOD_TRANSFUSION.toString());
+            for (Lemma lemma : bloodTransfusionLemmas) {
+                BloodTransfusion bloodTransfusion = new BloodTransfusion();
+                bloodTransfusion.setName(lemma.getText());
+                if (lemma.isHaveChildren()) {
+                    bloodTransfusion.setNegative(findNegative(lemma));
+                    bloodTransfusion.setQuantity(findT(lemma, new Quantity(), EntityEnum.QUANTITY.toString()));//数量
+                    bloodTransfusion.setPd(findPD(lemma));//时间
+                }
+                pastLabel.addBloodTransfusion(bloodTransfusion);
+            }
+            //预防接种史
+            List<Lemma> vaccinateLemmas = createEntityTree(aiOut, EntityEnum.VACCINATION.toString());
+            for (Lemma lemma : vaccinateLemmas) {
+                Vaccinate vaccinate = new Vaccinate();
+                vaccinate.setName(lemma.getText());
+                if (lemma.isHaveChildren()) {
+                    vaccinate.setNegative(findNegative(lemma));
+                }
+                pastLabel.addVaccinate(vaccinate);
+            }
+            //传染病史
+            List<Lemma> diagInfectiousLemmas = createEntityTree(aiOut, EntityEnum.INFECTIOUS_KEYWORD.toString());
+            for (Lemma lemma : diagInfectiousLemmas) {
+                DiagInfectious diagInfectious = new DiagInfectious();
+                diagInfectious.setName(lemma.getText());
+                if (lemma.isHaveChildren()) {
+                    diagInfectious.setNegative(findNegative(lemma));
+                }
+                pastLabel.addDiagInfectious(diagInfectious);
+            }
+
+            //健康情况
+            List<Lemma> healthLemmas = createEntityTree(aiOut, EntityEnum.HEALTH.toString());
+            for (Lemma lemma : healthLemmas) {
+                pastLabel.setHeathCondition(lemma.getText());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            logger.error(e.getMessage(), e);
+        }
+        return pastLabel;
+    }
+}

+ 138 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessPersonal.java

@@ -0,0 +1,138 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.*;
+import com.lantone.structure.model.label.PersonalLabel;
+
+import java.util.List;
+
+/**
+ * @ClassName : EntityProcessPersonal
+ * @Description : 个人史
+ * @Author : 楼辉荣
+ * @Date: 2020-03-10 10:20
+ */
+public class EntityProcessPersonal extends EntityProcess {
+    public PersonalLabel extractEntity(JSONObject aiOut) {
+        PersonalLabel personalLabel = new PersonalLabel();
+        //地点
+        List<Lemma> addressLemmas = createEntityTree(aiOut, EntityEnum.LOCATION.toString());
+        for (Lemma lemma :addressLemmas) {
+            Address address = new Address();
+            address.setName(lemma.getText());
+            personalLabel.addAddress(address);
+        }
+        //职业
+        List<Lemma> occupationLemmas = createEntityTree(aiOut, EntityEnum.OCCUPATION.toString());
+        for (Lemma lemma :occupationLemmas) {
+            Occupation occupation = new Occupation();
+            occupation.setName(lemma.getText());
+            personalLabel.setOccupation(occupation);
+        }
+        //疫区史
+        List<Lemma> fertilityLemmas = createEntityTree(aiOut, EntityEnum.EPIDEMIC_AREA_HISTORY.toString());
+        for (Lemma lemma :fertilityLemmas) {
+            EpidemicArea epidemicArea = new EpidemicArea();
+            epidemicArea.setName(lemma.getText());
+            personalLabel.setEpidemicArea(epidemicArea);
+        }
+        //接触史
+        List<Lemma> contactLemmas = createEntityTree(aiOut, EntityEnum.CONTACT_HISTORY.toString());
+        for (Lemma lemma :contactLemmas) {
+            Contact contact = new Contact();
+            contact.setName(lemma.getText());
+            personalLabel.setContact(contact);
+        }
+        //特殊嗜好
+        List<Lemma> specialHobbyLemmas = createEntityTree(aiOut, EntityEnum.SPECIAL_HOBBY.toString());
+        for (Lemma lemma :specialHobbyLemmas) {
+            SpecialHobby specialHobby = new SpecialHobby();
+            specialHobby.setName(lemma.getText());
+            //阴性
+            specialHobby.setNegative(findNegative(lemma));
+            personalLabel.setSpecialHobby(specialHobby);
+        }
+        //吸烟史
+        List<Lemma> smokingLemmas = createEntityTree(aiOut, EntityEnum.SMOKING_HISTORY.toString());
+        for (Lemma lemma :smokingLemmas) {
+            Smoking smoking = new Smoking();
+            smoking.setName(lemma.getText());
+            //阴性
+            smoking.setNegative(findNegative(lemma));
+            if (lemma.isHaveChildren()) {
+                for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                    if (relationLemma.getProperty().equals(EntityEnum.TIME.toString())) {
+                        smoking.setPd(addPD(relationLemma));
+                    } else if (relationLemma.getProperty().equals(EntityEnum.USAGE.toString())) {
+                        smoking.setUsage(addUsage(relationLemma));
+                    }
+                }
+            }
+            personalLabel.setSmoking(smoking);
+        }
+
+        //饮酒史
+        List<Lemma> drinkingLemmas = createEntityTree(aiOut, EntityEnum.HISTORY_OF_ALCOHOL_INTAKE.toString());
+        for (Lemma lemma :drinkingLemmas) {
+            Drinking drinking = new Drinking();
+            drinking.setName(lemma.getText());
+            //阴性
+            drinking.setNegative(findNegative(lemma));
+            if (lemma.isHaveChildren()) {
+                for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                    if (relationLemma.getProperty().equals(EntityEnum.TIME.toString())) {
+                        drinking.setPd(addPD(relationLemma));
+                    } else if (relationLemma.getProperty().equals(EntityEnum.USAGE.toString())) {
+                        drinking.setUsage(addUsage(relationLemma));
+                    }
+                }
+            }
+            personalLabel.setDrinking(drinking);
+        }
+
+        //用量 用于判断吸烟 和 饮酒符合规范
+        List<Lemma> usageLemmas = createEntityTree(aiOut, EntityEnum.USAGE.toString());
+        for (Lemma lemma :usageLemmas) {
+            Usage usage = new Usage();
+            usage.setName(lemma.getText());
+            personalLabel.setUsage(usage);
+        }
+
+        //冶游史
+        List<Lemma> maritalHistoryLemmas = createEntityTree(aiOut, EntityEnum.MARITAL_HISTORY.toString());
+        for (Lemma lemma :maritalHistoryLemmas) {
+            MaritalHistory maritalHistory = new MaritalHistory();
+            maritalHistory.setName(lemma.getText());
+            if (lemma.isHaveChildren()) {
+                maritalHistory.setNegative(findNegative(lemma));
+            }
+            personalLabel.setMaritalHistory(maritalHistory);
+        }
+        return personalLabel;
+    }
+
+    /**
+     * 时间
+     * @param timeLemma
+     * @return
+     */
+    private PD addPD(Lemma timeLemma) {
+        PD pd = new PD();
+        pd.setName(timeLemma.getText());
+        pd.setValue(timeLemma.getText());
+        return pd;
+    }
+
+    /**
+     * 用量
+     * @param usageLemma
+     * @return
+     */
+    private Usage addUsage(Lemma usageLemma) {
+        Usage usage = new Usage();
+        usage.setName(usageLemma.getText());
+        return usage;
+    }
+}

+ 375 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessThreeLevelWard.java

@@ -0,0 +1,375 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.*;
+import com.lantone.structure.model.label.ThreeLevelWardLabel;
+import com.lantone.common.util.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : EntityProcessThreeLevelWard
+ * @Description : 查房记录
+ * @Author : 胡敬
+ * @Date: 2020-03-20 11:20
+ */
+@Slf4j
+public class EntityProcessThreeLevelWard extends EntityProcess {
+    private List<String> titleList = Arrays.asList(
+            EntityEnum.TITLE_FOR_SIGN.toString(),
+            EntityEnum.TITLE_FOR_DIAG.toString(),
+            EntityEnum.TITLE_FOR_DIAG_BASIS.toString(),
+            EntityEnum.TITLE_FOR_DIFF.toString(),
+            EntityEnum.TITLE_FOR_TREAT.toString());
+
+    public ThreeLevelWardLabel extractEntity(JSONObject aiOut) {
+        ThreeLevelWardLabel threeLevelWardLabel = new ThreeLevelWardLabel();
+        String content = aiOut.getString("content");
+
+        Map<String, List<String>> titleText = subWithTitle(aiOut);
+        //全部临床表现实体
+        List<Lemma> clinicalLemmas = createEntityTree(aiOut, EntityEnum.CLINICAL_FEATURE.toString());
+        //全部诊断
+        List<Lemma> diagLemmas = createEntityTree(aiOut, EntityEnum.DIEASE.toString());
+        //诊断依据
+        if (titleText.get(EntityEnum.TITLE_FOR_DIAG_BASIS.toString()) != null) {
+            List<String> diagBasisList = titleText.get(EntityEnum.TITLE_FOR_DIAG_BASIS.toString());
+            String text = textJoin(content, diagBasisList);
+            String[] diagBasisSplit = String.join(",", diagBasisList).split(",");
+            //诊断依据文本
+            threeLevelWardLabel.setDiagBasisText(text);
+            //病史(在 诊断依据 以外的片段中出现 任一 临床表现)
+            addClinical(threeLevelWardLabel, diagBasisSplit, clinicalLemmas);
+            //补充诊断/初步诊断/修正诊断
+            addDiag(threeLevelWardLabel, diagBasisSplit, diagLemmas);
+        }
+
+        //诊断文本
+        if (titleText.get(EntityEnum.TITLE_FOR_DIAG.toString()) != null) {
+            List<String> diagList = titleText.get(EntityEnum.TITLE_FOR_DIAG.toString());
+            String text = textJoin(content, diagList);
+            //诊断文本
+            threeLevelWardLabel.setDiagText(text);
+        }
+
+        //鉴别诊断
+        if (titleText.get(EntityEnum.TITLE_FOR_DIFF.toString()) != null) {
+            List<String> diffDiagList = titleText.get(EntityEnum.TITLE_FOR_DIFF.toString());
+            String diagBasis = String.join(",", diffDiagList);
+            String[] diffDiagSplit = diagBasis.split(",");
+            //病史(在 鉴别诊断 以外的片段中出现 任一 临床表现)
+            addClinical(threeLevelWardLabel, diffDiagSplit, clinicalLemmas);
+            //补充诊断/初步诊断/修正诊断
+            addDiag(threeLevelWardLabel, diffDiagSplit, diagLemmas);
+            //添加鉴别诊断
+            List<Diag> diags = new ArrayList<>();
+            for (Lemma dieaseLemma : diagLemmas) {
+                if (Integer.parseInt(dieaseLemma.getPosition()) < Integer.parseInt(diffDiagSplit[0])
+                        || Integer.parseInt(dieaseLemma.getPosition()) > Integer.parseInt(diffDiagSplit[diffDiagSplit.length - 1])) {
+                    continue;
+                }
+                Diag diag = new Diag();
+                diag.setHospitalDiagName(dieaseLemma.getText());
+                diags.add(diag);
+            }
+            threeLevelWardLabel.setDiffDiag(diags);
+            List<Lemma> diagDiffLemmas = createEntityTree(aiOut, EntityEnum.TITLE_FOR_DIFF.toString());
+            for (Lemma lemma : diagDiffLemmas) {
+                if (lemma.getText().contains("诊断明确") || lemma.getText().contains("无需鉴别")) {
+                    threeLevelWardLabel.setDiffDiagText(lemma.getText());
+                    break;
+                }
+            }
+        }
+
+        //没有诊断依据和鉴别诊断情况下,添加诊断
+        if (titleText.get(EntityEnum.TITLE_FOR_DIAG_BASIS.toString()) == null
+                && titleText.get(EntityEnum.TITLE_FOR_DIFF.toString()) == null) {
+            //补充诊断/初步诊断/修正诊断
+            addDiag(threeLevelWardLabel, diagLemmas);
+        }
+
+        //查体
+        List<Lemma> signLemmas = createEntityTree(aiOut, EntityEnum.PHYSICAL_EXAMINATION.toString());
+        List<Sign> signs = new ArrayList<>();
+        for (Lemma lemma : signLemmas) {
+            Sign sign = new Sign();
+            sign.setName(lemma.getText());
+            signs.add(sign);
+        }
+        threeLevelWardLabel.setSigns(signs);
+
+        //诊疗计划
+        List<Lemma> treatmentPlanLemmas = createEntityTree(aiOut, EntityEnum.TREATMENT_PLAN.toString());
+        List<TreatmentPlan> treatmentPlans = new ArrayList<>();
+        for (Lemma lemma : treatmentPlanLemmas) {
+            TreatmentPlan treatmentPlan = new TreatmentPlan();
+            treatmentPlan.setName(lemma.getText());
+            treatmentPlans.add(treatmentPlan);
+        }
+        threeLevelWardLabel.setTreatmentPlans(treatmentPlans);
+
+        //离院方式
+        List<Lemma> dischargeMode = createEntityTree(aiOut, EntityEnum.DISCHARGE_MODE.toString());
+        for (Lemma lemma : dischargeMode) {
+            String text = lemma.getText();
+            threeLevelWardLabel.setDischargeMode(text);
+        }
+
+
+        //好转表现
+        List<Lemma> betterFindingLemmas = createEntityTree(aiOut, EntityEnum.BETTER_FINDING.toString());
+        List<BetterFinding> betterFindings = new ArrayList<>();
+        for (Lemma lemma : betterFindingLemmas) {
+            BetterFinding betterFinding = new BetterFinding();
+            betterFinding.setName(lemma.getText());
+            betterFindings.add(betterFinding);
+        }
+        threeLevelWardLabel.setBetterFindings(betterFindings);
+
+        //转归情况-好转
+        List<Lemma> outcomeToBetterLemmas = createEntityTree(aiOut, EntityEnum.OUTCOME_TO_BETTER.toString());
+        List<OutcomeToBetter> outcomeToBetters = new ArrayList<>();
+        for (Lemma lemma : outcomeToBetterLemmas) {
+            OutcomeToBetter outcomeToBetter = new OutcomeToBetter();
+            outcomeToBetter.setName(lemma.getText());
+            outcomeToBetters.add(outcomeToBetter);
+        }
+        threeLevelWardLabel.setOutcomeToBetters(outcomeToBetters);
+
+        //转归情况-治愈
+        List<Lemma> outcomeCureLemmas = createEntityTree(aiOut, EntityEnum.OUTCOME_CURE.toString());
+        List<OutcomeCure> outcomeCures = new ArrayList<>();
+        for (Lemma lemma : outcomeCureLemmas) {
+            OutcomeCure outcomeCure = new OutcomeCure();
+            outcomeCure.setName(lemma.getText());
+            outcomeCures.add(outcomeCure);
+        }
+        threeLevelWardLabel.setOutcomeCures(outcomeCures);
+
+        //阳性表现
+        List<Lemma> positiveFindingLemmas = createEntityTree(aiOut, EntityEnum.POSITIVE_FINDING.toString());
+        List<PositiveFinding> positiveFindings = new ArrayList<>();
+        for (Lemma lemma : positiveFindingLemmas) {
+            PositiveFinding positiveFinding = new PositiveFinding();
+            positiveFinding.setName(lemma.getText());
+            positiveFindings.add(positiveFinding);
+        }
+        threeLevelWardLabel.setPositiveFindings(positiveFindings);
+
+        try {
+            //实验室检查套餐
+            List<LaboratoryPackage> laboratoryPackages = new ArrayList<>();
+            List<Lemma> laboratoryPackageLemmas = createEntityTree(aiOut, EntityEnum.LABORATORY_PACKAGE.toString());
+            for (Lemma lemma : laboratoryPackageLemmas) {
+                LaboratoryPackage laboratoryPackage = new LaboratoryPackage();
+                laboratoryPackage.setName(lemma.getText());
+                laboratoryPackage.setCheckTime(findTAfter(lemma, new CheckTime(), EntityEnum.CHECK_TIME.toString()));
+                laboratoryPackages.add(laboratoryPackage);
+            }
+            threeLevelWardLabel.setLaboratoryPackages(laboratoryPackages);
+
+            //实验室检查
+            List<Laboratory> laboratories = new ArrayList<>();
+            List<Lemma> laboratoryLemmas = createEntityTree(aiOut, EntityEnum.LABORATORY.toString());
+            for (Lemma lemma : laboratoryLemmas) {
+                Laboratory laboratory = new Laboratory();
+                laboratory.setName(lemma.getText());
+                for (Lemma relationLemma : lemma.getRelationLemmas()) {
+                    if (relationLemma.getProperty().equals(EntityEnum.LABORATORY_PACKAGE.toString())) {
+                        LaboratoryPackage laboratoryPackage = new LaboratoryPackage();
+                        laboratoryPackage.setCheckTime(findTAfter(lemma, new CheckTime(), EntityEnum.CHECK_TIME.toString()));
+                        laboratory.setLaboratoryPackage(findTAfter(lemma, laboratoryPackage, EntityEnum.LABORATORY_PACKAGE.toString()));//实验室检查套餐
+                    }
+                }
+                laboratory.setCheckTime(findTAfter(lemma, new CheckTime(), EntityEnum.CHECK_TIME.toString()));//检查时间
+                laboratory.setLaboratoryResults(findTAfter(lemma, new LaboratoryResults(), EntityEnum.LABORATORY_RESULTS.toString()));//实验室检查结果
+                laboratories.add(laboratory);
+            }
+            threeLevelWardLabel.setLaboratories(laboratories);
+
+            //辅助检查
+            List<AuxiliaryExamination> auxiliaryExaminations = new ArrayList<>();
+            List<Lemma> auxiliaryExaminationLemmas = createEntityTree(aiOut, EntityEnum.AUXILIARY_EXAMINATION.toString());
+            for (Lemma lemma : auxiliaryExaminationLemmas) {
+                AuxiliaryExamination auxiliaryExamination = new AuxiliaryExamination();
+                auxiliaryExamination.setName(lemma.getText());
+                auxiliaryExamination.setCheckTime(findTAfter(lemma, new CheckTime(), EntityEnum.CHECK_TIME.toString()));
+                auxiliaryExamination.setAuxiliaryExaminationResults(findTAfter(lemma, new AuxiliaryExaminationResults(), EntityEnum.AUXILIARY_EXAMINATION_RESULTS.toString()));
+                auxiliaryExaminations.add(auxiliaryExamination);
+            }
+            threeLevelWardLabel.setAuxiliaryExaminations(auxiliaryExaminations);
+
+            //药物
+            List<Drug> drugs = new ArrayList<>();
+            List<Lemma> DrugLemmas = createEntityTree(aiOut, EntityEnum.DRUG.toString());
+            for (Lemma lemma : DrugLemmas) {
+                int lemmaPosition = Integer.parseInt(lemma.getPosition());
+                if (content.substring(Math.max(0, lemmaPosition - 10), lemmaPosition).contains("暂停")){
+                    continue;
+                }
+                Drug drug = new Drug();
+                drug.setName(lemma.getText().replaceAll("[“”]",""));
+                drug.setConsumption(findTAfter(lemma, new Consumption(), EntityEnum.CONSUMPTION.toString().split("-")[0]));
+                drug.setUsageWardRound(findTAfter(lemma, new UsageWardRound(), EntityEnum.USAGE_WARD_ROUND.toString()));
+                drug.setFrequency(findTAfter(lemma, new Frequency(), EntityEnum.FREQUENCY.toString()));
+                drug.setStop(findTAfter(lemma, new Stop(), EntityEnum.STOP.toString()));
+                drug.setReasonsForAntibiotic(findTAfter(lemma, new ReasonsForAntibiotic(), EntityEnum.REASONS_FOR_ANTIBIOTIC.toString()));
+                drugs.add(drug);
+            }
+            threeLevelWardLabel.setDrugs(drugs);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error(e.getMessage(), e);
+        }
+        return threeLevelWardLabel;
+    }
+
+    private String textJoin(String content, List<String> operativeFindingsList) {
+        StringBuffer text = new StringBuffer();
+        for (String titleTextIndex : operativeFindingsList) {
+            String[] titleTextIndexSplit = titleTextIndex.split(",");
+            text.append(content.substring(Integer.parseInt(titleTextIndexSplit[0]),
+                    Integer.parseInt(titleTextIndexSplit[1])));
+        }
+        return text.toString();
+    }
+
+    /**
+     * 根据各标题截取文本index
+     *
+     * @param aiOut
+     * @return
+     */
+    private Map<String, List<String>> subWithTitle(JSONObject aiOut) {
+        Map<String, List<String>> titleText = new LinkedHashMap<>();
+        String content = aiOut.getString("content");
+        List<Lemma> lemmaList = loadAllLemmaList(aiOut.getJSONObject("annotation").getJSONArray("T"));
+        Lemma lemma;
+        int start = 0;
+        String subContentIndex = "", title = "";
+        for (int i = 0; i < lemmaList.size(); i++) {
+            lemma = lemmaList.get(i);
+            if (!titleList.contains(lemma.getProperty()) && i != lemmaList.size() - 1) {
+                continue;
+            }
+            if (i != lemmaList.size() - 1) {
+                if (start == 0) {
+                    start = Integer.parseInt(lemma.getPosition());
+                    title = lemma.getProperty();//截取的这一段文本的标题
+                } else {
+                    /*subContentIndex = start + lemma.getText().length() + 1 + "," + Integer.parseInt(lemma.getPosition());*/
+                    subContentIndex = start + "," + Integer.parseInt(lemma.getPosition());
+                    putSubContent(titleText, title, subContentIndex);
+                    start = Integer.parseInt(lemma.getPosition());
+                    title = lemma.getProperty();//截取的这一段文本的标题
+                }
+            } else {
+                //将倒数第二个标题存入结构
+                if (StringUtil.isNotBlank(title)) {
+                    subContentIndex = start + "," + Integer.parseInt(lemma.getPosition());
+                    putSubContent(titleText, title, subContentIndex);
+                }
+                //如果是最后一个Lemma,文本就从当前lemma的position开始取,取到结束
+                title = lemma.getProperty();//截取的这一段文本的标题
+                if (titleList.contains(title)) {
+                    start = Integer.parseInt(lemma.getPosition());
+                    int lastIndex = content.length() - 1;
+                    subContentIndex = start + "," + lastIndex;
+                    putSubContent(titleText, title, subContentIndex);
+                }
+            }
+        }
+        return titleText;
+    }
+
+    private void putSubContent(Map<String, List<String>> titleText, String text, String subContent) {
+        List<String> textList;
+        if (titleText.containsKey(text)) {
+            titleText.get(text).add(subContent);
+        } else {
+            textList = new ArrayList<>();
+            textList.add(subContent);
+            titleText.put(text, textList);
+        }
+    }
+
+    /**
+     * 添加病史(临床表现)
+     *
+     * @param threeLevelWardLabel
+     * @param indexArray          标题对应文本全部起始位置、结束位置信息
+     * @param clinicalLemmas
+     */
+    private void addClinical(ThreeLevelWardLabel threeLevelWardLabel, String[] indexArray, List<Lemma> clinicalLemmas) {
+        List<Clinical> clinicals = new ArrayList<>();
+        for (Lemma lemma : clinicalLemmas) {
+            if (Integer.parseInt(lemma.getPosition()) > Integer.parseInt(indexArray[0])
+                    && Integer.parseInt(lemma.getPosition()) < Integer.parseInt(indexArray[indexArray.length - 1])) {
+                continue;
+            }
+            Clinical clinical = new Clinical();
+            clinical.setName(lemma.getText());
+            clinicals.add(clinical);
+        }
+        if (threeLevelWardLabel.getClinicals().size() == 0) {
+            threeLevelWardLabel.setClinicals(clinicals);
+        } else {
+            threeLevelWardLabel.getClinicals().addAll(clinicals);
+        }
+    }
+
+    /**
+     * 添加补充诊断/初步诊断/修正诊断
+     *
+     * @param threeLevelWardLabel
+     * @param indexArray          标题对应文本全部起始位置、结束位置信息
+     * @param diagLemmas
+     */
+    private void addDiag(ThreeLevelWardLabel threeLevelWardLabel, String[] indexArray, List<Lemma> diagLemmas) {
+        List<Diag> diags = new ArrayList<>();
+        for (Lemma lemma : diagLemmas) {
+            if (Integer.parseInt(lemma.getPosition()) > Integer.parseInt(indexArray[0])
+                    && Integer.parseInt(lemma.getPosition()) < Integer.parseInt(indexArray[indexArray.length - 1])) {
+                continue;
+            }
+            Diag diag = new Diag();
+            diag.setHospitalDiagName(lemma.getText());
+            diags.add(diag);
+        }
+        if (threeLevelWardLabel.getDiags().size() == 0) {
+            threeLevelWardLabel.setDiags(diags);
+        } else {
+            threeLevelWardLabel.getDiags().addAll(diags);
+        }
+    }
+
+    /**
+     * 没有诊断依据和鉴别诊断情况下,添加诊断
+     *
+     * @param threeLevelWardLabel
+     * @param diagLemmas
+     */
+    private void addDiag(ThreeLevelWardLabel threeLevelWardLabel, List<Lemma> diagLemmas) {
+        List<Diag> diags = new ArrayList<>();
+        for (Lemma lemma : diagLemmas) {
+            Diag diag = new Diag();
+            diag.setHospitalDiagName(lemma.getText());
+            diags.add(diag);
+        }
+        if (threeLevelWardLabel.getDiags().size() == 0) {
+            threeLevelWardLabel.setDiags(diags);
+        } else {
+            threeLevelWardLabel.getDiags().addAll(diags);
+        }
+    }
+
+}

+ 64 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessTreatPlan.java

@@ -0,0 +1,64 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.ai.model.Lemma;
+import com.lantone.structure.model.entity.*;
+import com.lantone.structure.model.label.TreatPlanLabel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @ClassName : EntityProcessTreatPlan
+ * @Description : 首次病程录--诊疗计划
+ * @Author : 楼辉荣
+ * @Date: 2020-03-19 15:45
+ */
+public class EntityProcessTreatPlan extends EntityProcess {
+    public TreatPlanLabel extractEntity(JSONObject aiOut) {
+        TreatPlanLabel treatPlanLabel = new TreatPlanLabel();
+        //护理级别
+        List<Lemma> nursingLevelLemmas = createEntityTree(aiOut, EntityEnum.NURSING_LEVEL.toString());
+        for (Lemma lemma :nursingLevelLemmas) {
+            NursingLevel nursingLevel = new NursingLevel();
+            nursingLevel.setName(lemma.getText());
+            treatPlanLabel.setNursingLevel(nursingLevel);
+        }
+        //药品
+        List<Lemma> medicineLemmas = createEntityTree(aiOut, EntityEnum.DRUG.toString());
+        for (Lemma lemma :medicineLemmas) {
+            Medicine medicine = new Medicine();
+            medicine.setName(lemma.getText());
+            treatPlanLabel.setMedicine(medicine);
+        }
+        //治疗或治疗目的
+        List<Lemma> treatLemmas = createEntityTree(aiOut, EntityEnum.TREAT_MENT.toString());
+        List<Treat> treats = new ArrayList<>();
+        for (Lemma lemma :treatLemmas) {
+            Treat treat = new Treat();
+            treat.setName(lemma.getText());
+            treats.add(treat);
+        }
+        treatPlanLabel.setTreat(treats);
+//        //化验
+//        List<Lemma> lisLemmas = createEntityTree(aiOut, EntityEnum.LABORATORY.toString());
+//        List<Lis> lises = new ArrayList<>();
+//        for (Lemma lemma :lisLemmas) {
+//            Lis lis = new Lis();
+//            lis.setName(lemma.getText());
+//            lises.add(lis);
+//        }
+//        treatPlanLabel.setLis(lises);
+        //检查
+        List<Lemma> pacsLemmas = createEntityTree(aiOut, EntityEnum.INSPECTION_ITEMS.toString());
+        List<Pacs> paces = new ArrayList<>();
+        for (Lemma lemma :pacsLemmas) {
+            Pacs pacs = new Pacs();
+            pacs.setName(lemma.getText());
+            paces.add(pacs);
+        }
+        treatPlanLabel.setPacs(paces);
+        return treatPlanLabel;
+    }
+}

+ 57 - 0
structure-center/src/main/java/com/lantone/structure/ai/process/EntityProcessVital.java

@@ -0,0 +1,57 @@
+package com.lantone.structure.ai.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lantone.structure.ai.model.EntityEnum;
+import com.lantone.structure.model.entity.*;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class EntityProcessVital extends EntityProcess {
+    public List<Vital> extractEntity(JSONObject outputs) {
+        List<Vital> vitals = new ArrayList<>();
+        Vital vital =null;
+        List<Map<String, String>> vitalEntityList = processJson(outputs, EntityEnum.SIGN.toString());
+        for (Map<String, String> vitalEntityMap : vitalEntityList) {
+            if (StringUtils.isEmpty(vitalEntityMap.get(EntityEnum.SIGN.toString()))) {
+                continue;
+            }
+            vital = new Vital();
+            for (String key:vitalEntityMap.keySet()) {
+                String entity = vitalEntityMap.get(key);
+                switch (EntityEnum.parseOfValue(key)) {
+                    case SIGN:
+                        vital.setVitalName(entity);
+                        break;
+                    case NEGATIVE:
+                        Negative negative = new Negative();
+                        negative.setName(entity);
+                        vital.setNegative(negative);
+                        break;
+                    case BODY:
+                        BodyPart bodyPart = new BodyPart();
+                        bodyPart.setName(entity);
+                        vital.setBodyPart(bodyPart);
+                        break;
+                    case INDEX_VALUE:
+                        vital.setValue(StringUtils.isEmpty(entity)?"":entity);
+                        PD pd =new PD();
+                        pd.setValue(StringUtils.isEmpty(entity)?"":entity);
+                        vital.setPd(pd);
+                        break;
+                    case MODIFICATION:
+                        if(entity.contains("度")){
+                            Degree degree = new Degree();
+                            degree.setName(entity);
+                            vital.setDegree(degree);
+                        }
+                        break;
+                }
+            }
+            vitals.add(vital);
+        }
+        return vitals;
+    }
+}

+ 23 - 0
structure-center/src/main/java/com/lantone/structure/client/CRFServiceClient.java

@@ -0,0 +1,23 @@
+package com.lantone.structure.client;
+
+
+import com.lantone.structure.model.vo.CRFVo;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+/**
+ * @Description: 调用条件随机场服务
+ * @author: Mark Huang
+ * @time: 2019/12/13 9:52
+ */
+@FeignClient(value = "CRF-service", url="${CRF.url}")
+public interface CRFServiceClient {
+
+    @PostMapping(value = "")
+    String getAnnotation(@RequestBody CRFVo crfVo);
+}
+
+
+

+ 23 - 0
structure-center/src/main/java/com/lantone/structure/client/ChiefPresentSimilarityServiceClient.java

@@ -0,0 +1,23 @@
+package com.lantone.structure.client;
+
+
+import com.lantone.structure.model.vo.ChiefPresentSimilarityVo;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+/**
+ * @Description: 调用主诉现病史症状相似度服务
+ * @author: 胡敬
+ * @time: 2020/06/01 15:41
+ */
+@FeignClient(value = "ChiefPresentSimilarity-service", url="${ChiefPresentSimilarity.url}")
+public interface ChiefPresentSimilarityServiceClient {
+
+    @PostMapping(value = "")
+    String getAnnotation(@RequestBody ChiefPresentSimilarityVo chiefPresentSimilarityVo);
+}
+
+
+

+ 23 - 0
structure-center/src/main/java/com/lantone/structure/client/NewSimilarityBatchServiceClient.java

@@ -0,0 +1,23 @@
+package com.lantone.structure.client;
+
+
+import com.alibaba.fastjson.JSONArray;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+/**
+ * @Description: 调用新文本相似度服务
+ * @author: 胡敬
+ * @time: 2020/08/26 13:43
+ */
+@FeignClient(value = "Similarity-new-batch-service", url="${NewBatchSimilarity.url}")
+public interface NewSimilarityBatchServiceClient {
+
+    @PostMapping(value = "")
+    String getAnnotation(@RequestBody JSONArray similarityVo);
+}
+
+
+

+ 23 - 0
structure-center/src/main/java/com/lantone/structure/client/NewSimilarityServiceClient.java

@@ -0,0 +1,23 @@
+package com.lantone.structure.client;
+
+
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+/**
+ * @Description: 调用文本相似度服务
+ * @author: 胡敬
+ * @time: 2020/08/26 13:43
+ */
+@FeignClient(value = "Similarity-new-service", url="${NewSimilarity.url}")
+public interface NewSimilarityServiceClient {
+
+    @PostMapping(value = "")
+    String getAnnotation(@RequestBody JSONObject similarityVo);
+}
+
+
+

+ 23 - 0
structure-center/src/main/java/com/lantone/structure/client/SimilarityServiceClient.java

@@ -0,0 +1,23 @@
+package com.lantone.structure.client;
+
+
+import com.lantone.structure.model.vo.SimilarityVo;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+/**
+ * @Description: 调用文本相似度服务
+ * @author: 胡敬
+ * @time: 2020/03/24 16:40
+ */
+@FeignClient(value = "Similarity-service", url="${Similarity.url}")
+public interface SimilarityServiceClient {
+
+    @PostMapping(value = "")
+    String getAnnotation(@RequestBody SimilarityVo similarityVo);
+}
+
+
+

+ 10 - 0
structure-center/src/main/java/com/lantone/structure/client/hystrix/CRFServiceHystrix.java

@@ -0,0 +1,10 @@
+package com.lantone.structure.client.hystrix;
+
+
+import org.springframework.stereotype.Component;
+
+
+@Component
+public class CRFServiceHystrix {
+
+}

+ 44 - 0
structure-center/src/main/java/com/lantone/structure/controller/DbController.java

@@ -0,0 +1,44 @@
+package com.lantone.structure.controller;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.dbanaly.facade.changx.ChangxXmlDataAnalysisFacade;
+import com.lantone.qc.dbanaly.facade.comsis.ModuleHelper;
+import com.lantone.qc.dbanaly.facade.comsis.RedisFacade;
+import com.lantone.qc.dbanaly.facade.shaoyf.ShaoyfXmlDataAnalysisFacade;
+import com.lantone.qc.dbanaly.facade.taizhou.TaiZhouXmlDataAnalysisFacade;
+import com.lantone.qc.dbanaly.facade.yiwu.YiWuXmlDataAnalysisFacade;
+import com.lantone.qc.dbanaly.vo.AnalyzeXmlVO;
+import com.lantone.qc.dbanaly.vo.CrfCacheRemoveVO;
+import com.lantone.qc.pub.res.Response;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @ClassName : QCController
+ * @Description : 质控总入口
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:57
+ */
+@Slf4j
+@Api(value = "数据对接接口", tags = { "数据对接接口" })
+@RestController
+@RequestMapping(value = "/db")
+public class DbController {
+
+    @ApiOperation(value = "模板信息加载")
+    @PostMapping("loadModuleInfo")
+    public Response<Boolean> loadModuleInfo() {
+        Response response = new Response();
+        response.setData(moduleHelper.loadModuleInfo());
+        return response;
+    }
+
+}

+ 9 - 0
structure-center/src/main/java/com/lantone/structure/dto/RespDTO.java

@@ -0,0 +1,9 @@
+package com.lantone.structure.dto;
+
+/**
+ * @Description:
+ * @author: rengb
+ * @time: 2020/12/18 16:10
+ */
+public class RespDTO {
+}

+ 317 - 0
structure-center/src/main/java/com/lantone/structure/model/Content.java

@@ -0,0 +1,317 @@
+/**
+ *	Content.java
+ *	医学病案质控病历内容标签
+ *
+ *	@author Mark Huang
+ *	@since 8/1/2020
+ **/
+package com.lantone.structure.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Content {
+
+    public static String title = "病历";
+    public static String header = "标题";
+    public static String content_lbl="内容";
+
+    public static String label = "content";
+
+    public static String[] docname = {"病案首页","入院记录","首次病程录","病程","医嘱","出院小结"};
+
+    public static List<String> title_homepage = Arrays.asList("医疗机构","医疗付费方式","健康卡号","住院次数"
+            ,"病案号","姓名","性别","出生日期","年龄","国籍","(年龄不足1周岁的)年龄","新生儿出生体重","新生儿入院体重"
+            ,"出生地","籍贯","民族","身份证号","职业","婚姻","现住址","户口地址","工作单位及地址"
+            ,"联系人姓名","入院途径","入院时间","出院时间","门(急)诊诊断","疾病编码","出院诊断","主要诊断","其他诊断"
+            ,"入院病情","损伤、中毒的外部因素"
+            ,"疾病代码","病理诊断","病理号","药物过敏","过敏药物","死亡患者尸检","血型","Rh","科主任","主任(副主任)医生"
+            ,"主治医师","住院医师","责任护士","进修医师","实习医师","编码员","病案质量","质控医师","质控护士","质控日期"
+            ,"手术操作码","手术操作日期","手术级别","手术及操作名称","手术及操作医师","术者"
+            ,"I助","II助","切口愈合等级","麻醉方式","麻醉医师","离院方式","拟接收医疗机构名称","是否有出院31天内再住院计划"
+            ,"目的","颅脑损伤患者昏迷时间","入院前天","入院后天","住院费用(元) : 总费用"
+            ,"1.综合医疗服务类","2.诊断类","3.治疗类", "4.康复类","5.中医类","6.西药类","7.中药类","8.血液和血液制品类",
+            "9.耗材类","10.其他类","单病种管理","临床路径管理","诊断符合情况","抢救情况","主要诊断治愈好转情况");
+
+    public static List<String> title_admit = Arrays.asList("姓名","性别","年龄","民族",
+            "职业","出生地","婚姻","联系地址","病史陈述者","入院日期","记录日期",
+            "主诉","现病史","既往史","个人史","月经史","婚育史","家族史","体格检查(一)",
+            "体格检查(二)","辅助检查","初步诊断","修正诊断","医师签名","补充诊断");
+
+    public static List<String> admit_basic = Arrays.asList("姓名","性别","年龄","民族",
+            "职业","出生地","婚姻","联系地址","病史陈述者","入院日期","记录日期");
+
+
+    public static List<String> title_progress = Arrays.asList("记录","记录医师");
+
+    public static List<String> title_first_progress = Arrays.asList("首次病程录","一、病例特点","二、初步诊断",
+            "三、诊断依据","四、鉴别诊断","五、诊疗计划","记录医师");
+
+    public static List<String> title_round = Arrays.asList("查房记录","记录医师");
+
+    public static List<String> title_critical_rec = Arrays.asList("危急值记录", "患者临床诊断", "危急值记录内容",
+            "报告部门","报告人姓名","报告时间","接收人姓名","接收时间","病情分析及处理","医生姓名","签名时间","记录医师");
+
+    public static List<String> title_transfusion = Arrays.asList("输血/血制品病程记录","输注原因","输注开始",
+            "输注结束","输注方式","输注种类、血型、数量","输注过程","输注后效果评价","记录医师");
+
+    public static List<String> title_preop_summary = Arrays.asList("术前讨论、术前小结","讨论方式","参加人员","简要病情",
+            "术前诊断","手术指征与禁忌征","可替代方案","拟施手术方式、名称及可能的变更","计划性多次手术","拟施麻醉方式"
+            ,"术前特殊准备","主要术中、术后风险及防范措施","术中、术后注意事项","经治医师签名","主刀医师签名");
+
+    public static List<String> title_operator_record = Arrays.asList("手术记录","手术时间","术前诊断","手术名称","手术中诊断",
+            "手术者","Ⅰ助","Ⅱ助","Ⅲ助","麻醉方式","麻醉人员","手术经过","手术者签字","记录时间");
+
+    public static List<String> title_postop_session = Arrays.asList("术后首次病程及谈话记录","手术时间","麻醉方式",
+            "手术名称","术中诊断","手术简要经过","患者术后情况","术后处理措施","术后可能出现的并发症及预防措施",
+            "术后注意事项","谈话医师签字","患者签名","被授权人/代理人签名");
+
+    public static List<String> title_decease_discuss = Arrays.asList("死亡病例讨论记录","入院时间","死亡时间","入院诊断",
+            "死亡诊断","讨论时间","讨论地点","参加讨论人员","讨论主持人","讨论内容","结论","记录医师");
+
+    public static List<String> title_decease_record = Arrays.asList("死亡记录","姓名","性别","科别","床号"
+            ,"病案号","年龄","入院时间","死亡时间","入院情况","入院诊断","诊疗经过","死亡原因","死亡诊断","记录医师"
+            ,"记录时间");
+
+    public static List<String> title_rescue = Arrays.asList("抢救记录","抢救时间","参加现场抢救的医师及护理人员",
+            "抢救过程","记录医师");
+
+    public static List<String> title_intractable_rec = Arrays.asList("疑难病例讨论记录","入院时间","入院诊断",
+            "讨论时间","讨论地点","讨论目的","主持人","参加讨论者(包括职称及姓名)","讨论内容","结论","记录医师");
+
+    public static List<String> title_phase_summary = Arrays.asList("阶段小结","入院日期","患者","入院情况","入院诊断",
+            "诊疗经过","目前情况","目前诊断","记录医师");
+
+    public static List<String> title_order = Arrays.asList("开始日期","开始时间","医嘱",
+            "结束日期","结束时间","医师签名","护士签名");
+
+    public static List<String> title_consultant = Arrays.asList("会诊记录","记录医师");
+
+    public static List<String> title_discharge = Arrays.asList("姓名","性别","年龄","床号",
+            "入院时间","出院时间","入院诊断","出院诊断","住院天数","入院情况", "诊治经过",
+            "出院情况","出院医嘱","健康教育","随访计划","温馨提示","医师签名","签名时间");
+
+    public static List<String> progress_type = Arrays.asList("查房记录","会诊记录","危急值记录","病重通知记录");
+
+
+    public static final String chief = "主诉";
+    public static final String present = "现病史";
+    public static final String past = "既往史";
+    public static final String personal = "个人史";
+    public static final String marriage = "婚育史";
+    public static final String menses = "月经史";
+    public static final String family = "家族史";
+    public static final String phys_exam = "体格检查(一)";
+    public static final String special_exam = "体格检查(二)";
+    public static final String pacs = "辅助检查";
+    public static final String initial_diag = "初步诊断";
+    public static final String revised_diag = "修正诊断";
+    public static final String supple_diag = "补充诊断";
+
+    public static final String case_feature = "一、病例特点";
+    public static final String pridiag = "二、初步诊断";
+    public static final String diag_basis = "三、诊断依据";
+    public static final String differential_diag_basis = "四、鉴别诊断";
+    public static final String treat_plan = "五、诊疗计划";
+
+    public static final String discharge = "出院小结";
+
+
+    public static final String name_medical_institution = "医疗机构名称";
+    public static final String code_medical_institution = "医疗机构代码";
+    public static final String medical_pay = "医疗付费方式";
+    public static final String codeId = "健康卡号";
+    public static final String hospitalizationNumber = "住院次数";
+    public static final String medical_recoder_number = "病案号";
+    public static final String name = "姓名";
+    public static final String gender = "性别";
+    public static final String age = "年龄";
+    public static final String nationality = "国籍";
+    public static final String birth_date = "出生日期";
+    public static final String newbornAgeMonths = "新生儿出生月数";
+    public static final String newbornAgeDays = "新生儿出生天数";
+    public static final String newbornWeight = "新生儿出生体重";
+    public static final String newbornAdmisWeight = "新生儿入院体重";
+    public static final String birth_address = "出生地";
+    public static final String native_place = "籍贯";
+    public static final String nation = "民族";
+    public static final String idNumber = "身份证号";
+    public static final String job = "职业";
+    public static final String marry = "婚姻";
+    public static final String current_address = "现住址";
+    public static final String current_address_phone = "现住址电话";
+    public static final String current_address_zipcode = "现住址邮编";
+    public static final String household_address = "户口地址";
+    public static final String household_address_zipcode = "户口地址邮编";
+    public static final String work_unit = "工作单位";
+    public static final String work_unit_phone = "工作单位电话";
+    public static final String work_unit_zipcode = "工作单位邮编";
+    public static final String contactName = "联系人姓名";
+    public static final String contact_relation = "联系人关系";
+    public static final String contact_address = "联系人地址";
+    public static final String contact_phone = "联系人电话";
+
+    public static final String diagnose_cts = "诊断符合情况";
+    public static final String o_i = "门诊与住院";
+    public static final String i_o = "入院与出院";
+    public static final String ob_oa = "术前与术后";
+    public static final String clinical_pathology = "临床与病理";
+    public static final String radiation_pathology = "放射与病理";
+
+    public static final String medical_classification = "病历分型";
+//    public static final String inStatus = "入院病情";
+
+    public static final String outpatientEmergencyDiag = "门急诊诊断";
+    public static final String diagCode = "诊断编码";
+    public static final String diagnoseName = "诊断名称";
+    public static final String inStatus = "入院情况";
+    public static final String out_status = "出院情况";
+    public static final String dischargeDiag = "出院诊断";
+    public static final String leaveHospitalDoctorAdvice = "出院医嘱";
+    public static final String dp_out = "损伤、中毒外部原因";
+    public static final String pathologyDiagnose = "病理诊断";
+    public static final String admitPath = "入院途径";
+    public static final String admisTime = "入院时间"; //病案首页用
+    public static final String admitDept = "入院科别";
+    public static final String admitHouse = "入院病房";
+    public static final String admitBedNumber = "入院床位号码";
+    public static final String transferDept = "转科科别";
+    public static final String dischargeTime = "出院时间";
+    public static final String outDept = "出院科别";
+    public static final String outHouse = "出院病房";
+    public static final String receivingOrganization = "接收机构名称";
+    public static final String actualStay = "实际住院天数";//病案首页用
+    public static final String drugAllergy = "药物过敏";
+    public static final String allergyDrug = "过敏药物";
+    public static final String deadAutopsy = "死亡患者尸检";
+    public static final String bloodType="血型";
+    public static final String rhFactor="Rh";
+    public static final String qc_quality="病案质量";
+    public static final String qc_date="质控日期";
+    public static final String qc_nurse="质控护士";
+    public static final String qc_doctor="质控医师";
+    public static final String ncoding_staff="编码员";
+    public static final String internship_doctor="实习医师";
+    public static final String engage_doctor="进修医师";
+    public static final String duty_nurse="责任护士";
+    public static final String hospitalization_doctor="住院医师";
+    public static final String indications_doctor="主治医师";
+    public static final String director_doctor="主任医师";
+    public static final String dept_doctor="科主任";
+
+    public static final String attend ="主治";
+    public static final String director="主任";
+
+    public static final String criticallyIllPatients="危重患者";
+    public static final String difficultPatients="疑难患者";
+    public static final String rescuingPatients="抢救患者";
+
+    public static final String operative_information="手术信息";
+    public static final String operative_code="手术编码";
+    public static final String operative_date="手术日期";
+    public static final String operative_degree="手术级别";
+    public static final String operative_name="手术名称";
+    public static final String operative_user="术者";
+    public static final String operative_assistant_first="一助";
+    public static final String operative_assistant_second="二助";
+    public static final String notch_grade="切口等级";
+    public static final String healing_level="愈合等级";
+    public static final String anesthesia_mode="麻醉方式";
+    public static final String anesthesia_doctor="麻醉医师";
+    public static final String operation_Discussion="术后首次病程及谈话记录";
+
+    public static final String outWay="离院方式";
+    public static final String brainInjuryComaBeforeDays="颅脑损伤患者昏迷前天数";
+    public static final String brainInjuryComaBeforeHours="颅脑损伤患者昏迷前小时";
+    public static final String brainInjuryComaBeforeMins="颅脑损伤患者昏迷前分钟";
+    public static final String brainInjuryComaAfterDays="颅脑损伤患者昏迷后天数";
+    public static final String brainInjuryComaAfterHours="颅脑损伤患者昏迷后小时";
+    public static final String brainInjuryComaAfterMins="颅脑损伤患者昏迷后分钟";
+    public static final String daCode="医嘱转院机构名称";
+    public static final String reHospitalization="三十一天内再住院计划";
+
+
+
+
+
+    public static final String type = "性";
+    public static final String otherCharge = "其他费用";
+    public static final String charge = "费用";
+    public static final String outcome = "转归情况";
+    public static final String clinical_pathway_management = "临床路径管理";
+    public static final String single_disease_management = "单病种管理";
+    public static final String rescue_condition = "抢救情况";
+
+
+    public static final String doctor_rank = "医师等级";
+    public static final String round_doctor = "查房医师";
+
+    public static final String admisDate = "入院日期"; //入院记录用
+    public static final String stayLength = "住院天数";//出院小结用
+
+    public static final String timestamp = "timestamp";
+
+    public static String[] dateFormats = {
+            "yyyy年MM月dd日HH时mm分",
+            "yyyy年MM月dd日HH:mm",
+            "yyyy年MM月dd日H时mm分",
+            "yyyy年MM月dd日HH时m分",
+            "yyyy年MM月dd日H时m分",
+            "yyyy年M月dd日HH时mm分",
+            "yyyy年M月dd日H时mm分",
+            "yyyy年M月dd日HH时m分",
+            "yyyy年M月dd日H时m分",
+            "yyyy年MM月d日HH时mm分",
+            "yyyy年MM月d日H时mm分",
+            "yyyy年MM月d日HH时m分",
+            "yyyy年MM月d日H时m分",
+            "yyyy年M月d日HH时mm分",
+            "yyyy年M月d日H时mm分",
+            "yyyy年M月d日HH时m分",
+            "yyyy年M月d日H时m分",
+            "yyyy-MM-ddHH:mm:ss",
+            "yyyy-MM-ddHH:mm",
+            "yyyy-MM-ddHH:mm",
+            "yyyy-MM-ddHH:m",
+            "yyyy-MM-ddH:mm",
+            "yyyy-MM-ddH:m",
+            "yyyy-M-ddHH:mm",
+            "yyyy-M-ddHH:m",
+            "yyyy-M-ddH:mm",
+            "yyyy-M-ddH:m",
+            "yyyy-MM-dHH:mm",
+            "yyyy-MM-dHH:m",
+            "yyyy-MM-dH:mm",
+            "yyyy-MM-dH:m",
+            "yyyy-M-dHH:mm",
+            "yyyy-M-dHH:m",
+            "yyyy-M-dH:mm",
+            "yyyy-M-dH:m",
+            "yyyy-MM-dd",
+            "yyyy年MM月dd日H时",
+            "yyyy/MM/ddHH:mm:ss",
+            "yyyy/MM/ddHH:mm",
+            "yyyy/MM/ddHH:m",
+            "yyyy/MM/ddH:mm",
+            "yyyy/MM/ddH:m",
+            "yyyy/MM/ddHH:mm:",
+            "yyyy/M/ddHH:mm",
+            "yyyy/M/ddHH:m",
+            "yyyy/M/ddH:mm",
+            "yyyy/M/ddH:m",
+            "yyyy/MM/dHH:mm",
+            "yyyy/MM/dHH:m",
+            "yyyy/MM/dH:mm",
+            "yyyy/MM/dH:m",
+            "yyyy/M/dHH:mm",
+            "yyyy/M/dHH:m",
+            "yyyy/M/dH:mm",
+            "yyyy/M/dH:m",
+            "yyyy/MM/dd",
+            "yyyy.MM.dd",
+            "yyyy-MM-ddHH:mm:ss.000",
+            "yyyyMMddHH:mm",
+            "yyyy-MM-dd'T'HH:mm:ss",
+            "yyyy-MM-ddTHH:mm:ss",
+    };
+}

+ 106 - 0
structure-center/src/main/java/com/lantone/structure/model/InputInfo.java

@@ -0,0 +1,106 @@
+package com.lantone.structure.model;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.lantone.structure.model.doc.*;
+import com.lantone.structure.model.doc.consultation.ConsultationDoc;
+import com.lantone.structure.model.doc.operation.OperationDoc;
+import com.lantone.structure.model.doc.transferrecord.TransferRecordDoc;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : InputInfo
+ * @Description : 医院质控病历录入对象
+ * @Author : 楼辉荣
+ * @Date: 2020-03-04 15:39
+ */
+@Getter
+@Setter
+public class InputInfo {
+
+    /**
+     * 将要执行的规则,precond--规则执行前置条件
+     * {"BEH0001":{"precond":"BEH0002,BEH0003,BEH0004"}}
+     */
+    private Map<String, Map<String, String>> inputCatalogueMap = new HashMap<>();
+    //页面结构化信息存储
+    private Map<String, Object> pageData = Maps.newHashMap();
+    //会诊
+    private List<ConsultationDoc> consultationDocs = new ArrayList<>();
+    //手术
+    private List<OperationDoc> operationDocs = new ArrayList<>();
+    //转科记录
+    private TransferRecordDoc transferRecordDocs;
+    //入院记录
+    private BeHospitalizedDoc beHospitalizedDoc;
+    //输血/血制品病程记录
+    private List<ClinicalBloodDoc> clinicalBloodDocs = new ArrayList<>();
+    //输血后效果评价
+    private List<ClinicBloodEffectDoc> clinicBloodEffectDocs = new ArrayList<>();
+    //危急值文书记录
+    private List<CrisisValueReportDoc> crisisValueReportDocs = new ArrayList<>();
+    //危急值结构化信息
+    private List<CrisisInfoDoc> crisisInfoDocs = new ArrayList<>();
+    //病危通知书
+    private List<CriticallyIllNoticeDoc> criticallyIllNoticeDocs = new ArrayList<>();
+    //死亡病例讨论记录
+    private DeathCaseDiscussDoc deathCaseDiscussDoc;
+    //死亡记录
+    private DeathRecordDoc deathRecordDoc;
+    //疑难病例讨论记录
+    private List<DifficultCaseDiscussDoc> difficultCaseDiscussDocs = new ArrayList<>();
+    //医嘱信息
+    private List<DoctorAdviceDoc> doctorAdviceDocs = new ArrayList<>();
+    //化验信息
+    private List<LisDoc> lisDocs = new ArrayList<>();
+    //辅检信息
+    private List<PacsDoc> pacsDocs = new ArrayList<>();
+    //值班交接制度
+    private List<DutyShiftSystemDoc> dutyShiftSystemDocs = new ArrayList<>();
+    //首次病程录
+    private FirstCourseRecordDoc firstCourseRecordDoc;
+    //病案首页
+    private FirstPageRecordDoc firstPageRecordDoc;
+    //出院小结
+    private LeaveHospitalDoc leaveHospitalDoc;
+    //分级护理制度
+    private NursingSystemDoc nursingSystemDoc;
+    //抢救记录
+    private List<RescueDoc> rescueDocs = new ArrayList<>();
+    //病重通知书
+    private List<SeriouslyIllNoticeDoc> seriouslyIllNoticeDocs = new ArrayList<>();
+    //阶段小结
+    private List<StagesSummaryDoc> stagesSummaryDocs = new ArrayList<>();
+    //查房记录
+    private List<ThreeLevelWardDoc> threeLevelWardDocs = new ArrayList<>();
+    //知情同意书
+    private InformedConsentDoc informedConsentDoc;
+    //谈话告知书
+    private NoticeOfConversationDoc noticeOfConversationDoc;
+    //麻醉相关
+    private List<AnesthesiaRelatedDoc> anesthesiaRelatedDocs = new ArrayList<>();
+    //有创操作记录
+    private List<InvasiveOperationDoc> invasiveOperationDocs = new ArrayList<>();
+    //病历书写规范
+    private List<MedicalWritingDoc> medicalWritingDocs = new ArrayList<>();
+    //病理检验送检单
+    private List<PathologyShipDoc> pathologyShipDocs = new ArrayList<>();
+    //诊疗合理性
+    private List<ReasonableDiagnosisDoc> reasonableDiagnosisDocs = new ArrayList<>();
+    //日常病程录
+    private List<DailyCourseRecordDoc> dailyCourseRecordDocs = Lists.newArrayList();
+    //住院病历信息
+    private MedicalRecordInfoDoc medicalRecordInfoDoc;
+    private boolean useCrfCache;
+
+    //新增记录
+    public <T> void addDoc(List<T> list, T obj) {
+        list.add(obj);
+    }
+}

+ 28 - 0
structure-center/src/main/java/com/lantone/structure/model/OutputInfo.java

@@ -0,0 +1,28 @@
+package com.lantone.structure.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @ClassName : OutputInfo
+ * @Description : 返回对象
+ * @Author : 楼辉荣
+ * @Date: 2020-03-04 15:50
+ */
+@Setter
+@Getter
+public class OutputInfo {
+    /**
+     * 如
+     * {
+     * "BEH001":{"status":"-1", "info": "发热"}
+     * }
+     */
+    private Map<String, Map<String, Object>> result = new HashMap<>();
+    //后结构化数据
+    private Map<String, Object> pageData = new HashMap<>();
+
+}

+ 10 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/AnesthesiaRelatedDoc.java

@@ -0,0 +1,10 @@
+package com.lantone.structure.model.doc;
+
+/**
+ * @ClassName : AnesthesiaRelatedDoc
+ * @Description :麻醉相关文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-30 10:08
+ */
+public class AnesthesiaRelatedDoc extends ModelDoc {
+}

+ 44 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/BeHospitalizedDoc.java

@@ -0,0 +1,44 @@
+package com.lantone.structure.model.doc;
+
+import com.lantone.structure.model.label.*;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : InHospitalDoc
+ * @Description : 入院记录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 18:58
+ */
+@Getter
+@Setter
+public class BeHospitalizedDoc extends ModelDoc {
+    //主诉
+    private ChiefLabel chiefLabel;
+    //现病史
+    private PresentLabel presentLabel;
+    //既往史
+    private PastLabel pastLabel;
+    //个人史
+    private PersonalLabel personalLabel;
+    //婚育史
+    private MaritalLabel maritalLabel;
+    //月经史
+    private MenstrualLabel menstrualLabel;
+    //家族史
+    private FamilyLabel familyLabel;
+    //体格检查
+    private VitalLabel vitalLabel;
+    //专科体格检查
+    private VitalLabelSpecial vitalLabelSpecial;
+    //辅助检查
+    private PacsLabel pacsLabel;
+    //实验室检查
+    private LisLabel lisLabel;
+    //初步诊断
+    private DiagLabel initialDiagLabel;
+    //修正诊断
+    private DiagLabel revisedDiagLabel;
+    //补充诊断
+    private DiagLabel suppleDiagLabel;
+}

+ 10 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/ClinicBloodEffectDoc.java

@@ -0,0 +1,10 @@
+package com.lantone.structure.model.doc;
+
+/**
+ * @ClassName : ClinicBloodEffectDoc
+ * @Description : 输血效果评价
+ * @Author : 楼辉荣
+ * @Date: 2020-04-19 17:47
+ */
+public class ClinicBloodEffectDoc extends ModelDoc {
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/ClinicalBloodDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : ClinicalBloodDoc
+ * @Description : 输血/血制品病程记录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:08
+ */
+@Getter
+@Setter
+public class ClinicalBloodDoc extends ModelDoc {
+}

+ 14 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/CrisisInfoDoc.java

@@ -0,0 +1,14 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 危急值结构化信息
+ * @author: rengb
+ * @time: 2020/3/20 15:47
+ */
+@Getter
+@Setter
+public class CrisisInfoDoc extends ModelDoc {
+}

+ 14 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/CrisisValueReportDoc.java

@@ -0,0 +1,14 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 危急值记录文档
+ * @author: rengb
+ * @time: 2020/3/19 19:27
+ */
+@Getter
+@Setter
+public class CrisisValueReportDoc extends ModelDoc {
+}

+ 14 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/CriticallyIllNoticeDoc.java

@@ -0,0 +1,14 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 病危通知书文档
+ * @author: rengb
+ * @time: 2020/3/20 14:03
+ */
+@Setter
+@Getter
+public class CriticallyIllNoticeDoc extends ModelDoc {
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/DailyCourseRecordDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : RescueDoc
+ * @Description : 日常病程录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-17 15:14
+ */
+@Setter
+@Getter
+public class DailyCourseRecordDoc extends ModelDoc {
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/DeathCaseDiscussDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : DeathCaseDiscussionDoc
+ * @Description : 死亡病例讨论记录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:02
+ */
+@Getter
+@Setter
+public class DeathCaseDiscussDoc extends ModelDoc {
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/DeathRecordDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : DeathRecordDoc
+ * @Description : 死亡记录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:11
+ */
+@Getter
+@Setter
+public class DeathRecordDoc extends ModelDoc {
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/DifficultCaseDiscussDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : DifficultCaseDiscussDoc
+ * @Description : 疑难病例讨论记录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:03
+ */
+@Getter
+@Setter
+public class DifficultCaseDiscussDoc extends ModelDoc {
+}

+ 14 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/DoctorAdviceDoc.java

@@ -0,0 +1,14 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 医嘱信息文档
+ * @author: rengb
+ * @time: 2020/3/20 15:47
+ */
+@Getter
+@Setter
+public class DoctorAdviceDoc extends ModelDoc {
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/DutyShiftSystemDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : DutyShiftSystemDoc
+ * @Description : 值班交接制度文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:08
+ */
+@Getter
+@Setter
+public class DutyShiftSystemDoc extends ModelDoc {
+}

+ 28 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/FirstCourseRecordDoc.java

@@ -0,0 +1,28 @@
+package com.lantone.structure.model.doc;
+
+import com.lantone.structure.model.label.*;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : FirstCourseRecordDoc
+ * @Description : 首次病程录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:01
+ */
+@Getter
+@Setter
+public class FirstCourseRecordDoc extends ModelDoc {
+    //初步诊断
+    private DiagLabel initialDiagLabel;
+    //病历特点
+    private CaseCharacteristicLabel caseCharacteristicLabel;
+    //诊断依据
+    private DiagnosisLabel diagnosisLabel;
+    //鉴别诊断
+    private DiagLabel differentialDiagLabel;
+    //诊疗计划
+    private TreatPlanLabel treatPlanLabel;
+    //药品-抗生素
+    private DrugLabel drugLabel;
+}

+ 19 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/FirstPageRecordDoc.java

@@ -0,0 +1,19 @@
+package com.lantone.structure.model.doc;
+
+import com.google.common.collect.Maps;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FirstPageRecordDoc
+ * @Description : 病案首页文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:05
+ */
+@Getter
+@Setter
+public class FirstPageRecordDoc extends ModelDoc {
+    private Map<String, Object> structureExtMap = Maps.newHashMap();
+}

+ 9 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/InformedConsentDoc.java

@@ -0,0 +1,9 @@
+package com.lantone.structure.model.doc;
+
+/**
+ * @Description: 知情同意书
+ * @author: wangyu
+ * @time: 2020/4/20 18:18
+ */
+public class InformedConsentDoc extends ModelDoc {
+}

+ 10 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/InvasiveOperationDoc.java

@@ -0,0 +1,10 @@
+package com.lantone.structure.model.doc;
+
+/**
+ * @ClassName : InvasiveOperationDoc
+ * @Description : 有创操作记录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-30 10:13
+ */
+public class InvasiveOperationDoc extends ModelDoc {
+}

+ 20 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/LeaveHospitalDoc.java

@@ -0,0 +1,20 @@
+package com.lantone.structure.model.doc;
+
+import com.lantone.structure.model.label.*;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : LeaveHospitalDoc
+ * @Description : 出院小结文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 18:58
+ */
+@Getter
+@Setter
+public class LeaveHospitalDoc extends ModelDoc {
+    private LeaveHospitalLabel leaveHospitalLabel;
+    private LeaveHospitalDoctorAdviceLabel leaveHospitalDoctorAdviceLabel;//出院医嘱
+    private DiagLabel beHospitalizedLabel;//入院诊断
+    private DiagLabel leaveDiagLabel;//出院诊断
+}

+ 14 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/LisDoc.java

@@ -0,0 +1,14 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 化验文档
+ * @author: rengb
+ * @time: 2020/3/20 15:47
+ */
+@Getter
+@Setter
+public class LisDoc extends ModelDoc {
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/MedicalRecordInfoDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : MedicalRecordInfoDoc
+ * @Description : 住院病历信息
+ * @Author : 胡敬
+ * @Date: 2020-06-03 15:46
+ */
+@Getter
+@Setter
+public class MedicalRecordInfoDoc extends ModelDoc {
+}

+ 10 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/MedicalWritingDoc.java

@@ -0,0 +1,10 @@
+package com.lantone.structure.model.doc;
+
+/**
+ * @ClassName : MedicalWritingDoc
+ * @Description : 病历书写规范文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-30 10:10
+ */
+public class MedicalWritingDoc extends ModelDoc {
+}

+ 22 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/ModelDoc.java

@@ -0,0 +1,22 @@
+package com.lantone.structure.model.doc;
+
+import com.google.common.collect.Maps;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+/**
+ * @Description: 模块文档
+ * @author: rengb
+ * @time: 2020/3/17 13:58
+ */
+@Getter
+@Setter
+public class ModelDoc {
+    //所有结构化信息存储
+    private Map<String, String> structureMap = Maps.newHashMap();
+    private String text;
+    //页面结构化信息存储
+    private Map<String, Object> pageData = Maps.newHashMap();
+}

+ 17 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/NoticeOfConversationDoc.java

@@ -0,0 +1,17 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * @Description: 谈话告知书
+ * @author: wangyu
+ * @time: 2020/4/20 18:18
+ */
+@Getter
+@Setter
+public class NoticeOfConversationDoc extends ModelDoc {
+    public List<String> allNoticeOfConverstartion;//所有的告知书
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/NursingSystemDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : NursingSystemDoc
+ * @Description : 分级护理制度文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:07
+ */
+@Getter
+@Setter
+public class NursingSystemDoc extends ModelDoc {
+}

+ 14 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/PacsDoc.java

@@ -0,0 +1,14 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 辅检文档
+ * @author: HUJING
+ * @time: 2020/8/14 13:16
+ */
+@Getter
+@Setter
+public class PacsDoc extends ModelDoc {
+}

+ 10 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/PathologyShipDoc.java

@@ -0,0 +1,10 @@
+package com.lantone.structure.model.doc;
+
+/**
+ * @ClassName : PathologyShipDoc
+ * @Description :病理检验送检单
+ * @Author : 楼辉荣
+ * @Date: 2020-04-19 17:48
+ */
+public class PathologyShipDoc extends ModelDoc {
+}

+ 10 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/ReasonableDiagnosisDoc.java

@@ -0,0 +1,10 @@
+package com.lantone.structure.model.doc;
+
+/**
+ * @ClassName : ReasonableDiagnosisDoc
+ * @Description : 诊疗合理性文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-30 10:12
+ */
+public class ReasonableDiagnosisDoc extends ModelDoc {
+}

+ 15 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/RescueDoc.java

@@ -0,0 +1,15 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @ClassName : RescueDoc
+ * @Description : 抢救记录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-17 15:14
+ */
+@Setter
+@Getter
+public class RescueDoc extends ModelDoc {
+}

+ 14 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/SeriouslyIllNoticeDoc.java

@@ -0,0 +1,14 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 病重通知书文档
+ * @author: rengb
+ * @time: 2020/3/20 14:01
+ */
+@Setter
+@Getter
+public class SeriouslyIllNoticeDoc extends ModelDoc {
+}

+ 14 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/StagesSummaryDoc.java

@@ -0,0 +1,14 @@
+package com.lantone.structure.model.doc;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 阶段小结文档
+ * @author: rengb
+ * @time: 2020/3/23 11:25
+ */
+@Getter
+@Setter
+public class StagesSummaryDoc extends ModelDoc {
+}

+ 121 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/ThreeLevelWardDoc.java

@@ -0,0 +1,121 @@
+package com.lantone.structure.model.doc;
+
+import com.lantone.structure.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.structure.model.doc.ward.DirectorDoctorWardDoc;
+import com.lantone.structure.model.doc.ward.GeneralDoctorWardDoc;
+import com.lantone.structure.model.label.ThreeLevelWardLabel;
+import com.lantone.common.util.StringUtil;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * @ClassName : ThreeLevelWardDoc
+ * @Description : 查房记录文档
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:04
+ */
+@Getter
+@Setter
+public class ThreeLevelWardDoc extends ModelDoc {
+    private List<ThreeLevelWardLabel> threeLevelWardLabel = new ArrayList<>();
+    //所有的查房记录
+    private List<ThreeLevelWardDoc> allDoctorWradDocs = new ArrayList<>();
+    //主任医师查房
+    private List<DirectorDoctorWardDoc> directorDoctorWardDocs = new ArrayList<>();
+    //主治医师查房
+    private List<AttendingDoctorWardDoc> attendingDoctorWardDocs = new ArrayList<>();
+    //普通医师查房
+    private List<GeneralDoctorWardDoc> generalDoctorWardDocs = new ArrayList<>();
+
+    /**
+     * 总的查房记录集合
+     * @param allDoctorWradDoc
+     */
+    public void addAllDoctorWradDoc(ThreeLevelWardDoc allDoctorWradDoc) {
+        if (StringUtil.isBlank(allDoctorWradDoc.getStructureMap().get("查房日期"))){
+            return;
+        }
+        Map<Date, ThreeLevelWardDoc> dateRecord = new TreeMap<>(new Comparator<Date>() {
+            @Override
+            public int compare(Date o1, Date o2) {
+                // 升序排列
+                return o1.compareTo(o2);
+            }
+        });//按时间key排序,查房记录
+        dateRecord.put(StringUtil.parseDateTime(allDoctorWradDoc.getStructureMap().get("查房日期")), allDoctorWradDoc);
+        allDoctorWradDocs.stream().forEach(
+                doc ->  dateRecord.put(StringUtil.parseDateTime(doc.getStructureMap().get("查房日期")), doc)
+        );
+
+        List<ThreeLevelWardDoc> docs = new ArrayList<>(dateRecord.values());
+        allDoctorWradDocs = docs;
+    }
+
+    public void addDirectorDoctorWardDoc(DirectorDoctorWardDoc directorDoctorWardDoc) {
+        if (StringUtil.isBlank(directorDoctorWardDoc.getStructureMap().get("查房日期"))){
+            return;
+        }
+        Map<Date, DirectorDoctorWardDoc> dateRecord = new TreeMap<>(new Comparator<Date>() {
+            @Override
+            public int compare(Date o1, Date o2) {
+                // 升序排列
+                return o1.compareTo(o2);
+            }
+        });//按时间key排序,存放查房记录
+        dateRecord.put(StringUtil.parseDateTime(directorDoctorWardDoc.getStructureMap().get("查房日期")), directorDoctorWardDoc);
+        directorDoctorWardDocs.stream().forEach(
+             doc ->  dateRecord.put(StringUtil.parseDateTime(doc.getStructureMap().get("查房日期")), doc)
+        );
+
+        List<DirectorDoctorWardDoc> docs = new ArrayList<>(dateRecord.values());
+        directorDoctorWardDocs = docs;
+    }
+
+    public void addAttendingDoctorWardDoc(AttendingDoctorWardDoc attendingDoctorWardDoc) {
+        if (StringUtil.isBlank(attendingDoctorWardDoc.getStructureMap().get("查房日期"))){
+            return;
+        }
+        Map<Date, AttendingDoctorWardDoc> dateRecord = new TreeMap<>(new Comparator<Date>() {
+            @Override
+            public int compare(Date o1, Date o2) {
+                // 升序排列
+                return o1.compareTo(o2);
+            }
+        });//按时间key排序,存放查房记录
+        dateRecord.put(StringUtil.parseDateTime(attendingDoctorWardDoc.getStructureMap().get("查房日期")), attendingDoctorWardDoc);
+        attendingDoctorWardDocs.stream().forEach(
+                doc ->  dateRecord.put(StringUtil.parseDateTime(doc.getStructureMap().get("查房日期")), doc)
+        );
+
+        List<AttendingDoctorWardDoc> docs = new ArrayList<>(dateRecord.values());
+        attendingDoctorWardDocs = docs;
+    }
+
+    public void addGeneralDoctorWardDoc(GeneralDoctorWardDoc generalDoctorWardDoc) {
+        if (StringUtil.isBlank(generalDoctorWardDoc.getStructureMap().get("查房日期"))){
+            return;
+        }
+        Map<Date, GeneralDoctorWardDoc> dateRecord = new TreeMap<>(new Comparator<Date>() {
+            @Override
+            public int compare(Date o1, Date o2) {
+                // 升序排列
+                return o1.compareTo(o2);
+            }
+        });//按时间key排序,存放查房记录
+        dateRecord.put(StringUtil.parseDateTime(generalDoctorWardDoc.getStructureMap().get("查房日期")), generalDoctorWardDoc);
+        generalDoctorWardDocs.stream().forEach(
+                doc ->  dateRecord.put(StringUtil.parseDateTime(doc.getStructureMap().get("查房日期")), doc)
+        );
+
+        List<GeneralDoctorWardDoc> docs = new ArrayList<>(dateRecord.values());
+        generalDoctorWardDocs = docs;
+
+    }
+}

+ 16 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/consultation/ConsultationApplicationDoc.java

@@ -0,0 +1,16 @@
+package com.lantone.structure.model.doc.consultation;
+
+import com.lantone.structure.model.doc.ModelDoc;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 会诊申请单文档
+ * @author: rengb
+ * @time: 2020/3/28 10:56
+ */
+@Getter
+@Setter
+public class ConsultationApplicationDoc extends ModelDoc {
+    private String consultationName;
+}

+ 20 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/consultation/ConsultationDoc.java

@@ -0,0 +1,20 @@
+package com.lantone.structure.model.doc.consultation;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 会诊文档
+ * @author: rengb
+ * @time: 2020/3/28 10:52
+ */
+@Getter
+@Setter
+public class ConsultationDoc {
+
+    private String consultationName;
+    private ConsultationRecordDoc consultationRecordDoc;
+    private ConsultationResultsDoc consultationResultsDoc;
+    private ConsultationApplicationDoc consultationApplicationDoc;
+
+}

+ 16 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/consultation/ConsultationRecordDoc.java

@@ -0,0 +1,16 @@
+package com.lantone.structure.model.doc.consultation;
+
+import com.lantone.structure.model.doc.ModelDoc;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @Description: 会诊记录文档
+ * @author: rengb
+ * @time: 2020/3/28 10:53
+ */
+@Getter
+@Setter
+public class ConsultationRecordDoc extends ModelDoc {
+    private String consultationName;
+}

+ 0 - 0
structure-center/src/main/java/com/lantone/structure/model/doc/consultation/ConsultationResultsDoc.java


Some files were not shown because too many files changed in this diff