Browse Source

fix
患者列表

lifang 3 tháng trước cách đây
mục cha
commit
cca29c4806

+ 5 - 4
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/properties/ALiYunProperties.java

@@ -12,10 +12,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 @Data
 @ConfigurationProperties(prefix = "aliyun")
 public class ALiYunProperties {
-
-    private String appId;
-    private String apiKey;
-
     private String llmApiKey;
     private String llmModel;
 
@@ -27,6 +23,11 @@ public class ALiYunProperties {
      */
     private Agent imAgent;
 
+    /**
+     * 手麻单识别智能体
+     */
+    private Agent imageAgent;
+
     @Data
     public static class Agent{
         private String appId;

+ 1 - 3
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/service/ALiYunService.java

@@ -16,6 +16,4 @@ public interface ALiYunService {
     List<WxDoctorClinicRoomThumbnailVO> recognizeImage(MultipartFile file) throws Exception;
 
     String createMemory() throws Exception;
-
-    void recognizeImageCommit(MultipartFile file);
-}
+}

+ 94 - 37
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/service/impl/ALiYunServiceImpl.java

@@ -4,17 +4,28 @@ import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import cn.tr.module.smart.app.controller.vo.WxDoctorClinicRoomThumbnailVO;
+import cn.tr.module.smart.common.dto.BizQuestionDTO;
 import cn.tr.module.smart.common.po.BizDeptPO;
 import cn.tr.module.smart.common.properties.ALiYunProperties;
 import cn.tr.module.smart.common.repository.BizDeptRepository;
 import cn.tr.module.smart.common.service.ALiYunService;
 import cn.tr.module.sys.storage.dto.SysStorageRecordDTO;
 import cn.tr.module.sys.storage.service.IStorageFileService;
+import com.alibaba.dashscope.aigc.generation.Generation;
+import com.alibaba.dashscope.aigc.generation.GenerationParam;
+import com.alibaba.dashscope.aigc.generation.GenerationResult;
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
 import com.alibaba.dashscope.app.Application;
 import com.alibaba.dashscope.app.ApplicationParam;
 import com.alibaba.dashscope.app.ApplicationResult;
+import com.alibaba.dashscope.common.Message;
+import com.alibaba.dashscope.common.MultiModalMessage;
+import com.alibaba.dashscope.common.Role;
 import com.aliyun.teaopenapi.models.Config;
 import com.aliyun.teaopenapi.models.OpenApiRequest;
 import com.aliyun.teaopenapi.models.Params;
@@ -78,9 +89,77 @@ public class ALiYunServiceImpl implements ALiYunService {
         }
     }
 
+//    @Override
+//    public List<WxDoctorClinicRoomThumbnailVO> recognizeImage(MultipartFile file) throws Exception {
+//        List<WxDoctorClinicRoomThumbnailVO> result = new ArrayList<>();
+//        List<BizDeptPO> deptList = deptRepository.selectList(new LambdaQueryWrapper<>());
+//
+//        //使用缓存模版
+//        String prompt = promptTemplate;
+//
+//        if (CollectionUtil.isNotEmpty(deptList)) {
+//            prompt=String.format(prompt,
+//                    JSONUtil.toJsonStr( deptList.stream()
+//                            .map(dept->
+//                                    MapUtil.builder()
+//                                            .put("deptName",dept.getName())
+//                                            .put("deptId",dept.getId())
+//                                            .build()
+//                            )
+//
+//                            .collect(Collectors.toList())));
+//        }
+//        String imageUrl;
+//        SysStorageRecordDTO uploadResult = null;
+//        try {
+//            uploadResult= fileService.upload(
+//                    null,
+//                    null,
+//                    file.getOriginalFilename(),
+//                    file.getBytes(),
+//                    null);
+//            imageUrl = uploadResult.getAbsolutePath();
+//
+//            ApplicationParam param = ApplicationParam.builder()
+//                    .appId(aliyunProperties.getImageAgent().getAppId())
+//                    .apiKey(aliyunProperties.getImageAgent().getApiKey())
+//                    .prompt(prompt)
+//                    .images(Collections.singletonList(imageUrl))
+//                    .build();
+//
+//            Application app = new Application();
+//            ApplicationResult response = app.call(param);
+//            String jsonResponse = response.getOutput().getText();
+//
+//            String cleanedJson = cleanMarkdownJson(jsonResponse);
+//
+//            ObjectMapper objectMapper = new ObjectMapper();
+//
+//            if (cleanedJson.trim().startsWith("[")) {
+//                List<Map<String, Object>> patientList = objectMapper.readValue(
+//                        cleanedJson,
+//                        new TypeReference<List<Map<String, Object>>>() {}
+//                );
+//                if(CollectionUtil.isNotEmpty(patientList)){
+//                    return patientList.stream()
+//                            .map(info ->
+//                                    JSONUtil.toBean(JSONUtil.toJsonStr(info), WxDoctorClinicRoomThumbnailVO.class)
+//                            )
+//                            .filter(info-> StrUtil.isNotEmpty(info.getPatientCode()))
+//                            .collect(Collectors.toList());
+//                }
+//            }
+//        }finally {
+//            if (ObjectUtil.isNotNull(uploadResult)) {
+//                fileService.remove(Arrays.asList(uploadResult.getId()));
+//            }
+//        }
+//        return result;
+//    }
+
+
     @Override
     public List<WxDoctorClinicRoomThumbnailVO> recognizeImage(MultipartFile file) throws Exception {
-        List<WxDoctorClinicRoomThumbnailVO> result = new ArrayList<>();
         List<BizDeptPO> deptList = deptRepository.selectList(new LambdaQueryWrapper<>());
 
         //使用缓存模版
@@ -107,47 +186,30 @@ public class ALiYunServiceImpl implements ALiYunService {
                     file.getOriginalFilename(),
                     file.getBytes(),
                     null);
-
             imageUrl = uploadResult.getAbsolutePath();
 
-            ApplicationParam param = ApplicationParam.builder()
-                    .appId(aliyunProperties.getAppId())
-                    .apiKey(aliyunProperties.getApiKey())
-                    .prompt(prompt)
-                    .images(Collections.singletonList(imageUrl))
+            MultiModalConversation conv = new MultiModalConversation();
+            MultiModalMessage systemMessage = MultiModalMessage.builder().role(Role.SYSTEM.getValue())
+                    .content(Arrays.asList(
+                            Collections.singletonMap("text", "你是一位经验丰富的医院主任医师,擅长从医疗文档中提取关键信息,并将其转换为结构化的JSON格式"))).build();
+            MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
+                    .content(Arrays.asList(
+                            Collections.singletonMap("image", imageUrl),
+                            Collections.singletonMap("text", prompt))).build();
+            MultiModalConversationParam param = MultiModalConversationParam.builder()
+                    .apiKey(aliyunProperties.getImageAgent().getApiKey())
+                    .model("qwen3-vl-plus-2025-09-23")  // 此处以qwen-vl-max-latest为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/models
+                    .messages(Arrays.asList(systemMessage, userMessage))
                     .build();
-
-            Application app = new Application();
-            ApplicationResult response = app.call(param);
-            String jsonResponse = response.getOutput().getText();
-
-            String cleanedJson = cleanMarkdownJson(jsonResponse);
-
-            ObjectMapper objectMapper = new ObjectMapper();
-
-            if (cleanedJson.trim().startsWith("[")) {
-                List<Map<String, Object>> patientList = objectMapper.readValue(
-                        cleanedJson,
-                        new TypeReference<List<Map<String, Object>>>() {}
-                );
-                if(CollectionUtil.isNotEmpty(patientList)){
-                    return patientList.stream()
-                            .map(info ->
-                                    JSONUtil.toBean(JSONUtil.toJsonStr(info), WxDoctorClinicRoomThumbnailVO.class)
-                            )
-                            .filter(info-> StrUtil.isNotEmpty(info.getPatientCode()))
-                            .collect(Collectors.toList());
-                }
-            }
+            MultiModalConversationResult result = conv.call(param);
+            return JSONUtil.toList(String.valueOf(result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text")), WxDoctorClinicRoomThumbnailVO.class);
         }finally {
             if (ObjectUtil.isNotNull(uploadResult)) {
                 fileService.remove(Arrays.asList(uploadResult.getId()));
             }
         }
-        return result;
     }
 
-
     /**
      * 创建长期记忆体
      *
@@ -200,11 +262,6 @@ public class ALiYunServiceImpl implements ALiYunService {
         throw new Exception("无法从响应中提取memoryId: " + response);
     }
 
-    @Override
-    public void recognizeImageCommit(MultipartFile file) {
-
-    }
-
     private String cleanMarkdownJson(String jsonResponse) {
         return jsonResponse
                 .replaceFirst("^\\s*```json\\s*", "")

+ 15 - 5
tr-modules/tr-module-smartFollowUp/src/main/resources/llm/prompt.txt

@@ -3,7 +3,7 @@
 
 ## 技能
 ### 技能 1: 提取图片内容
-- 从提供的图片中提取手术相关信息。
+- 从提供的图片中提取一个或多个的手术相关信息。
 - 将提取的信息按照指定的JSON格式进行整理和输出。
 
 ### 技能 2: 处理不完整或无法识别的信息
@@ -12,9 +12,9 @@
 ## 限制
 - 只返回提取后的JSON格式数据,不添加任何额外的文字或解释。
 - 确保JSON格式严格按照用户提供的模板进行组织。
-- 如果图片中的信息不完整或无法识别,请在相应字段中填写"未知"或"未提供"。
+- 如果图片中的信息不完整或无法识别,请在除了年龄和手术时间的相应字段中填写"未知"或"未提供",如果年龄和手术时间无法识别,字段置空即可。
+
 
-```json
 [
     {
         "clinicName": "手术名称",
@@ -26,9 +26,19 @@
         "patientGender": "患者性别(男:MAN,女:WOMAN)",
         "deptName":"从我所给你的科室信息中选择相应的科室id,必填项",
         "deptId":"从我所给你的科室信息中选择相应的科室名称,必填项"
-    }
+    },
+    {
+            "clinicName": "手术名称2",
+            "patientCode": "住院号2",
+            "clinicStartTime": "手术时间2",
+            "patientName": "患者姓名2",
+            "patientGender": "患者性别2",
+            "patientAge": "患者年龄2",
+            "patientGender": "患者性别(男:MAN,女:WOMAN)",
+            "deptName":"从我所给你的科室信息中选择相应的科室id,必填项",
+            "deptId":"从我所给你的科室信息中选择相应的科室名称,必填项"
+        }
 ]
-```
 
 请根据提供的图片内容,填充上述JSON模板并返回。如果某些信息无法从图片中获取,请在相应的字段中填写""。
 

+ 4 - 2
tr-test/src/main/resources/application-dev.yml

@@ -50,8 +50,6 @@ wx:
 
 # 添加aliyun配置
 aliyun:
-  appId: "b95862368a65422eab15d9838a03b79f"
-  apiKey: "sk-b08f4aaed4d641e5ba049c34a0eaf377"
   llmApiKey: "sk-6038043b063c4f9eaadb497ec2fff50f"
   llmModel: "qwen3-30b-a3b-instruct-2507"
   aliAppKey: "LTAI4G7FA9ytMc76oNkJ45YJ"
@@ -60,4 +58,8 @@ aliyun:
     workplaceId: "llm-9othch7n7k4ue9uh"
     appId: "c71fc69490c0430186321c219fdd33dd"
     apiKey: "sk-6038043b063c4f9eaadb497ec2fff50f"
+  imageAgent:
+    workplaceId: "llm-9othch7n7k4ue9uh"
+    appId: "8d8f926e83514ed4a9f5b62e17412f8f"
+    apiKey: "sk-6038043b063c4f9eaadb497ec2fff50f"