Преглед изворни кода

字段标准化修改-台州邵逸夫入北仑

rengb пре 4 година
родитељ
комит
a149009881

+ 14 - 9
kernel/src/main/java/com/lantone/qc/kernel/structure/ai/ThreeLevelWardAI.java

@@ -2,6 +2,7 @@ package com.lantone.qc.kernel.structure.ai;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
 import com.lantone.qc.kernel.client.CRFServiceClient;
 import com.lantone.qc.kernel.structure.ai.process.EntityProcessThreeLevelWard;
 import com.lantone.qc.kernel.util.CatalogueUtil;
@@ -16,13 +17,9 @@ import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
 import com.lantone.qc.pub.util.ListUtil;
 import com.lantone.qc.pub.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.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * @ClassName : ThreeLevelWardAI
@@ -34,7 +31,7 @@ public class ThreeLevelWardAI extends ModelAI {
     /**
      *
      */
-    public static List<String> medicalTextType = Arrays.asList("CourseRecord_cx", "CourseRecordLast_cx");
+    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";
@@ -64,10 +61,18 @@ public class ThreeLevelWardAI extends ModelAI {
             putContent(crfContent, medicalTextType.get(0), lastDirStructureMap.get("病情记录"), Content.director + "最后一次");
         }
 
-        List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();//所有查房记录
+        //所有查房记录,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<>();

+ 29 - 3
kernel/src/main/java/com/lantone/qc/kernel/structure/ai/model/EntityEnum.java

@@ -18,7 +18,7 @@ public enum EntityEnum {
     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("肿瘤病史"),
+    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("注意事项"),
@@ -27,8 +27,10 @@ public enum EntityEnum {
     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("出院方式");
+    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;
 
@@ -235,6 +237,30 @@ public enum EntityEnum {
             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;
     }

+ 19 - 0
kernel/src/main/java/com/lantone/qc/kernel/structure/ai/process/EntityProcess.java

@@ -241,6 +241,25 @@ public class EntityProcess {
         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

+ 27 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/ai/process/EntityProcessPacs.java

@@ -3,16 +3,22 @@ package com.lantone.qc.kernel.structure.ai.process;
 import com.alibaba.fastjson.JSONObject;
 import com.lantone.qc.kernel.structure.ai.model.EntityEnum;
 import com.lantone.qc.kernel.structure.ai.model.Lemma;
+import com.lantone.qc.kernel.util.DiagEnhancer;
 import com.lantone.qc.pub.model.entity.BodyPart;
+import com.lantone.qc.pub.model.entity.Diag;
 import com.lantone.qc.pub.model.entity.OuterCourtyard;
 import com.lantone.qc.pub.model.entity.PD;
 import com.lantone.qc.pub.model.entity.Pacs;
 import com.lantone.qc.pub.model.entity.PacsValue;
+import com.lantone.qc.pub.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) {
         //辅检情况
@@ -34,12 +40,32 @@ public class EntityProcessPacs extends EntityProcess {
             }
             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 pacs = new Pacs();
+            pacs = new Pacs();
             pacs.setPd(pd);
             pacses.add(pacs);
         }

+ 77 - 16
kernel/src/main/java/com/lantone/qc/kernel/structure/ai/process/EntityProcessThreeLevelWard.java

@@ -3,21 +3,12 @@ package com.lantone.qc.kernel.structure.ai.process;
 import com.alibaba.fastjson.JSONObject;
 import com.lantone.qc.kernel.structure.ai.model.EntityEnum;
 import com.lantone.qc.kernel.structure.ai.model.Lemma;
-import com.lantone.qc.pub.model.entity.BetterFinding;
-import com.lantone.qc.pub.model.entity.Clinical;
-import com.lantone.qc.pub.model.entity.Diag;
-import com.lantone.qc.pub.model.entity.OutcomeCure;
-import com.lantone.qc.pub.model.entity.OutcomeToBetter;
-import com.lantone.qc.pub.model.entity.PositiveFinding;
-import com.lantone.qc.pub.model.entity.Sign;
-import com.lantone.qc.pub.model.entity.TreatmentPlan;
+import com.lantone.qc.pub.model.entity.*;
 import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
+import com.lantone.qc.pub.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;
+import java.util.*;
 
 /**
  * @ClassName : EntityProcessThreeLevelWard
@@ -25,6 +16,7 @@ import java.util.Map;
  * @Author : 胡敬
  * @Date: 2020-03-20 11:20
  */
+@Slf4j
 public class EntityProcessThreeLevelWard extends EntityProcess {
     private List<String> titleList = Arrays.asList(
             EntityEnum.TITLE_FOR_SIGN.toString(),
@@ -56,7 +48,7 @@ public class EntityProcessThreeLevelWard extends EntityProcess {
         }
 
         //诊断文本
-        if (titleText.get(EntityEnum.TITLE_FOR_DIAG.toString()) != null){
+        if (titleText.get(EntityEnum.TITLE_FOR_DIAG.toString()) != null) {
             List<String> diagList = titleText.get(EntityEnum.TITLE_FOR_DIAG.toString());
             String text = textJoin(content, diagList);
             //诊断文本
@@ -167,6 +159,73 @@ public class EntityProcessThreeLevelWard extends EntityProcess {
             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;
     }
 
@@ -211,8 +270,10 @@ public class EntityProcessThreeLevelWard extends EntityProcess {
                 }
             } else {
                 //将倒数第二个标题存入结构
-                subContentIndex = start + "," + Integer.parseInt(lemma.getPosition());
-                putSubContent(titleText, title, subContentIndex);
+                if (StringUtil.isNotBlank(title)) {
+                    subContentIndex = start + "," + Integer.parseInt(lemma.getPosition());
+                    putSubContent(titleText, title, subContentIndex);
+                }
                 //如果是最后一个Lemma,文本就从当前lemma的position开始取,取到结束
                 title = lemma.getProperty();//截取的这一段文本的标题
                 if (titleList.contains(title)) {

+ 151 - 0
kernel/src/main/java/com/lantone/qc/kernel/util/SimilarityUtil.java

@@ -0,0 +1,151 @@
+package com.lantone.qc.kernel.util;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Maps;
+import com.lantone.qc.kernel.client.NewSimilarityBatchServiceClient;
+import com.lantone.qc.kernel.client.NewSimilarityServiceClient;
+import com.lantone.qc.pub.util.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description:
+ * @author: rengb
+ * @time: 2020/8/24 10:06
+ */
+@Slf4j
+@Component
+public class SimilarityUtil {
+
+    @Autowired
+    private NewSimilarityServiceClient newSimilarityServiceClient;
+
+    @Autowired
+    private NewSimilarityBatchServiceClient newSimilarityBatchServiceClient;
+
+    /**
+     * 根据相似度,获取药品标准词
+     *
+     * @param drugWord
+     * @return
+     */
+    @Cacheable(value = "drugCache", key = "#drugWord", unless = "#result == null")
+    public String getDrugStandardWord(String drugWord) {
+        String ret = null;
+        try {
+            JSONArray standardWords = similarityRequest("drug", drugWord, 1);
+            if (standardWords != null && standardWords.size() == 1) {
+                JSONObject standardWord = standardWords.getJSONObject(0);
+                if (standardWord.getDoubleValue("rate") > 0.8) {
+                    ret = standardWord.getString("standard_word");
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        return ret;
+    }
+
+    /**
+     * 发送相似度请求
+     *
+     * @param word_type 由服务方定的词的类型,取值:疾病—disease、症状—symptom、手术和操作—operation、药品—drug、实验室检查-lis、辅助检查-pacs、体征-vital
+     * @param word      原始词
+     * @param number    最多返回个数,如果不是有效的值,默认返回1个,最多返回10个
+     * @return 返回具体数据集合
+     */
+    public JSONArray similarityRequest(String word_type, String word, int number) {
+        if (StringUtil.isBlank(word_type) || StringUtil.isBlank(word) || number == 0) {
+            return null;
+        }
+        JSONArray ret = null;
+        try {
+            JSONObject detailContent = new JSONObject();
+            detailContent.put("word_type", word_type);
+            detailContent.put("word", word);
+            detailContent.put("number", number);
+            String similarJson = newSimilarityServiceClient.getAnnotation(detailContent);
+            JSONObject similarJsonObject = JSON.parseObject(similarJson);
+            if (similarJsonObject.getBooleanValue("status")) {
+                ret = similarJsonObject.getJSONArray("standard_words");
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        return ret;
+    }
+
+    /**
+     * 根据相似度,获取药品标准词
+     *
+     * @param input
+     * @param wordType
+     * @return
+     */
+    public Map<String, String> getDrugStandardWordBatch(List<String> input, String wordType) {
+        Map<String, String> wordMap = Maps.newHashMap();
+        JSONArray inputData = new JSONArray();
+        JSONObject micro = null;
+        JSONObject similarJsonObject = null;
+        JSONArray ret = null;
+        try {
+            for (String word : input) {
+                micro = new JSONObject();
+                micro.put("word_type", wordType);
+                micro.put("word", word);
+                micro.put("number", 1);
+                inputData.add(micro);
+            }
+            if (inputData.size() > 0) {
+                JSONObject data = similarityBatchRequest(inputData);
+                JSONObject wordTypeJson = data.getJSONObject(wordType);
+                for (String word : input) {
+                    similarJsonObject = wordTypeJson.getJSONObject(word);
+                    if (similarJsonObject != null && similarJsonObject.getBooleanValue("status")) {
+                        ret = similarJsonObject.getJSONArray("standard_words");
+                        if (ret != null && ret.size() == 1) {
+                            JSONObject standardWord = ret.getJSONObject(0);
+                            if (standardWord.getDoubleValue("rate") > 0.8) {
+                                String result = standardWord.getString("standard_word");
+                                wordMap.put(word, result);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        return wordMap;
+    }
+
+    /**
+     * 发送相似度批量请求
+     *
+     * @param jsonArray 全部需要查询的标准词封装后的集合
+     * @return 返回具体数据集合
+     */
+    public JSONObject similarityBatchRequest(JSONArray jsonArray) {
+        if (jsonArray.size() == 0) {
+            return null;
+        }
+        JSONObject ret = null;
+        try {
+            String similarJson = newSimilarityBatchServiceClient.getAnnotation(jsonArray);
+            JSONObject similarJsonObject = JSON.parseObject(similarJson);
+            if (similarJsonObject.getBooleanValue("status")) {
+                ret = similarJsonObject.getJSONObject("data");
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        return ret;
+    }
+}