Parcourir la source

feat(member): 用户信息 AI 功能增强

- 新增 dataDual 方法处理图片和文件上传
- 更新 UserInfoAiDO 和相关 VO 类,增加 infoFiles 和 additionalInfo 字段
- 修改 UserInfoAiServiceImpl,支持新的 AI 数据处理功能
-优化 CodegenBuilder,自动识别图片、文件等类型字段
zrd il y a 3 mois
Parent
commit
03b0c4bedf

+ 30 - 0
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/AiFrameworkUtils.java

@@ -1,10 +1,15 @@
 package cn.iocoder.yudao.framework.dict.core;
 
 import cn.iocoder.yudao.module.infra.api.ai.AiApi;
+import cn.iocoder.yudao.module.infra.api.ai.dto.DifyReqDTO;
 import cn.iocoder.yudao.module.infra.api.ai.dto.DifyaiReqDTO;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
 /**
  * 字典工具类
  *
@@ -29,6 +34,31 @@ public class AiFrameworkUtils {
         return api.ai(createReqVO);
     }
     
+    @SneakyThrows
+    public static String dataDual(List<String> files) {
+        DifyReqDTO createReqVO = new DifyReqDTO();
+        String oldDomain = "https://zjkdywd.com:9014";
+        String newDomain = "http://42.194.163.46:9007";
+        
+        for (String file : files) {
+            List<Map<String, Object>> images = new ArrayList<>();
+            String replacedFile = file.replace(oldDomain, newDomain);
+            
+            if (replacedFile.endsWith(".png") || replacedFile.endsWith(".jpg") || replacedFile.endsWith(".jpeg")) {
+                if (createReqVO.getImages() == null) {
+                    createReqVO.setImages(new ArrayList<>());
+                }
+                createReqVO.getImages().add(replacedFile);
+            } else {
+                if (createReqVO.getDocs() != null) {
+                    createReqVO.setDocs(new ArrayList<>());
+                }
+                createReqVO.getDocs().add(replacedFile);
+            }
+        }
+        return api.dataDual(createReqVO);
+    }
+    
     @SneakyThrows
     public static String getHtml(String type, String content) {
         DifyaiReqDTO createReqVO = new DifyaiReqDTO();

+ 2 - 1
yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/ai/AiApi.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.infra.api.ai;
 
+import cn.iocoder.yudao.module.infra.api.ai.dto.DifyReqDTO;
 import cn.iocoder.yudao.module.infra.api.ai.dto.DifyaiReqDTO;
 import cn.iocoder.yudao.module.infra.api.ai.dto.StreamResponseDTO;
 import reactor.core.publisher.Flux;
@@ -13,7 +14,7 @@ import java.util.Map;
  */
 public interface AiApi {
     
-    
+    String dataDual(DifyReqDTO createReqVO);
     String ai(DifyaiReqDTO createReqVO);
     
     String html(DifyaiReqDTO createReqVO);

+ 21 - 0
yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/ai/dto/DifyReqDTO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.infra.api.ai.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class DifyReqDTO {
+    
+    
+    /**
+     * 事件类型
+     */
+    private List<String> images;
+    /**
+     * 内容
+     */
+    private List<String> docs;
+    
+    
+}

+ 35 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/ai/AiApiImpl.java

@@ -1,8 +1,10 @@
 package cn.iocoder.yudao.module.infra.api.ai;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
+import cn.iocoder.yudao.module.infra.api.ai.dto.DifyReqDTO;
 import cn.iocoder.yudao.module.infra.api.ai.dto.DifyaiReqDTO;
 import cn.iocoder.yudao.module.infra.api.ai.dto.StreamResponseDTO;
 import cn.iocoder.yudao.module.infra.service.aipromptmanagement.WorkflowRunService;
@@ -12,7 +14,9 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 import reactor.core.publisher.Flux;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -40,6 +44,37 @@ public class AiApiImpl implements AiApi {
         return workflowRunService.getDifyResul(inputs, createReqVO.getType(), apiKey, 1L);
     }
     
+    @Override
+    public String dataDual(DifyReqDTO createReqVO) {
+        Map<String, Object> inputs = new HashMap<>();
+        String apiKey = DictFrameworkUtils.parseDictDataValue("ai_key", "数据提取");
+        List<Map<String, Object>> images = new ArrayList<>();
+        if (CollUtil.isNotEmpty(createReqVO.getImages())) {
+            for (String image : createReqVO.getImages()) {
+                Map<String, Object> variableValue = new HashMap<>();
+                variableValue.put("transfer_method", "remote_url");
+                variableValue.put("url", image);
+                variableValue.put("type", "image");
+                images.add(variableValue);
+            }
+            
+            inputs.put("images", images);
+        }
+        if (CollUtil.isNotEmpty(createReqVO.getDocs())) {
+            for (String image : createReqVO.getImages()) {
+                Map<String, Object> variableValue = new HashMap<>();
+                variableValue.put("transfer_method", "remote_url");
+                variableValue.put("url", image);
+                variableValue.put("type", "document");
+                images.add(variableValue);
+                inputs.put("docs", images);
+            }
+        }
+        
+        
+        return workflowRunService.getDifyResul(inputs, "createReqVO.getType()", apiKey, 1L);
+    }
+    
     @Override
     public String html(DifyaiReqDTO createReqVO) {
         Map<String, Object> inputs = new HashMap<>();

+ 9 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilder.java

@@ -136,6 +136,15 @@ public class CodegenBuilder {
                 column.setHtmlType(CodegenColumnHtmlTypeEnum.SELECT.getType());
                 column.setColumnComment(subBefore(column.getColumnComment(), "#", false));
             }
+            if (column.getColumnComment().contains("头像") || column.getColumnComment().contains("图片")) {
+                column.setHtmlType(CodegenColumnHtmlTypeEnum.IMAGE_UPLOAD.getType());
+            }
+            if (column.getColumnComment().contains("文件") || column.getColumnComment().contains("附件")) {
+                column.setHtmlType(CodegenColumnHtmlTypeEnum.FILE_UPLOAD.getType());
+            }
+            if (column.getColumnComment().contains("内容") || column.getColumnComment().contains("信息")) {
+                column.setHtmlType(CodegenColumnHtmlTypeEnum.TEXTAREA.getType());
+            }
             // 初始化 Column 列的默认字段
             processColumnOperation(column); // 处理 CRUD 相关的字段的默认值
             processColumnUI(column); // 处理 UI 相关的字段的默认值

+ 6 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/userinfoai/vo/UserInfoAiPageReqVO.java

@@ -7,7 +7,9 @@ import lombok.EqualsAndHashCode;
 import lombok.ToString;
 import org.springframework.format.annotation.DateTimeFormat;
 
+import java.io.Serial;
 import java.time.LocalDateTime;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
@@ -17,6 +19,8 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @ToString(callSuper = true)
 public class UserInfoAiPageReqVO extends PageParam {
     
+    @Serial
+    private static final long serialVersionUID = -7285021790521397887L;
     @Schema(description = "用户编号", example = "25439")
     private Long userId;
     
@@ -32,5 +36,6 @@ public class UserInfoAiPageReqVO extends PageParam {
     
     @Schema(description = "是否选中#info_status", example = "1")
     private String infoStatus;
-    
+    private List<String> infoFiles;
+    private String additionalInfo;
 }

+ 3 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/userinfoai/vo/UserInfoAiRespVO.java

@@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
 import java.time.LocalDateTime;
+import java.util.List;
 
 @Schema(description = "管理后台 - 用户信息 Response VO")
 @Data
@@ -35,5 +36,6 @@ public class UserInfoAiRespVO {
     @Schema(description = "是否选中#info_status", example = "1")
     @ExcelProperty("是否选中#info_status")
     private String infoStatus;
-    
+    private List<String> infoFiles;
+    private String additionalInfo;
 }

+ 4 - 3
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/userinfoai/vo/UserInfoAiSaveReqVO.java

@@ -1,9 +1,10 @@
 package cn.iocoder.yudao.module.member.controller.admin.userinfoai.vo;
 
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
+import java.util.List;
+
 @Schema(description = "管理后台 - 用户信息新增/修改 Request VO")
 @Data
 public class UserInfoAiSaveReqVO {
@@ -12,7 +13,6 @@ public class UserInfoAiSaveReqVO {
     private Long id;
     
     @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25439")
-    @NotNull(message = "用户编号不能为空")
     private Long userId;
     
     @Schema(description = "提取有效信息")
@@ -23,5 +23,6 @@ public class UserInfoAiSaveReqVO {
     
     @Schema(description = "是否选中#info_status", example = "1")
     private String infoStatus;
-    
+    private List<String> infoFiles;
+    private String additionalInfo;
 }

+ 11 - 2
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/userinfoai/UserInfoAiDO.java

@@ -1,17 +1,22 @@
 package cn.iocoder.yudao.module.member.dal.dataobject.userinfoai;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
 import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.*;
 
+import java.io.Serial;
+import java.util.List;
+
 /**
  * 用户信息 DO
  *
  * @author 芋道源码
  */
-@TableName("member_user_info_ai")
+@TableName(value = "member_user_info_ai", autoResultMap = true)
 @KeySequence("member_user_info_ai_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -21,6 +26,8 @@ import lombok.*;
 @AllArgsConstructor
 public class UserInfoAiDO extends BaseDO {
     
+    @Serial
+    private static final long serialVersionUID = -2862594944368551619L;
     /**
      * 自增主键
      */
@@ -42,5 +49,7 @@ public class UserInfoAiDO extends BaseDO {
      * 是否选中#info_status
      */
     private String infoStatus;
-    
+    @TableField(typeHandler = StringListTypeHandler.class)
+    private List<String> infoFiles;
+    private String additionalInfo;
 }

+ 19 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/userinfoai/UserInfoAiServiceImpl.java

@@ -4,10 +4,13 @@ import cn.iocoder.yudao.framework.common.exception.BaseErrorCodeConstants;
 import cn.iocoder.yudao.framework.common.exception.util.CommonValidationUtils;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.dict.core.AiFrameworkUtils;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.module.member.controller.admin.userinfoai.vo.UserInfoAiPageReqVO;
 import cn.iocoder.yudao.module.member.controller.admin.userinfoai.vo.UserInfoAiSaveReqVO;
 import cn.iocoder.yudao.module.member.dal.dataobject.userinfoai.UserInfoAiDO;
 import cn.iocoder.yudao.module.member.dal.mysql.userinfoai.UserInfoAiMapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
@@ -26,8 +29,17 @@ public class UserInfoAiServiceImpl implements UserInfoAiService {
     
     @Override
     public Long createUserInfoAi(UserInfoAiSaveReqVO createReqVO) {
+        // 更新其他的 userId 和type的 状态为0
+        userInfoAiMapper.
+                update(new LambdaUpdateWrapper<UserInfoAiDO>()
+                        .eq(UserInfoAiDO::getUserId, SecurityFrameworkUtils.getLoginUserId())
+                        .eq(UserInfoAiDO::getInformationType, createReqVO.getInformationType())
+                        .setSql("info_Status =0"));
         // 插入
         UserInfoAiDO userInfoAi = BeanUtils.toBean(createReqVO, UserInfoAiDO.class);
+        userInfoAi.setUserId(SecurityFrameworkUtils.getLoginUserId());
+        userInfoAi.setInfoStatus("1");
+        userInfoAi.setTextInformation(AiFrameworkUtils.dataDual(createReqVO.getInfoFiles()));
         userInfoAiMapper.insert(userInfoAi);
         // 返回
         return userInfoAi.getId();
@@ -38,6 +50,13 @@ public class UserInfoAiServiceImpl implements UserInfoAiService {
         // 校验存在
         validateUserInfoAiExists(updateReqVO.getId());
         // 更新
+        userInfoAiMapper.
+                update(new LambdaUpdateWrapper<UserInfoAiDO>()
+                        .eq(UserInfoAiDO::getUserId, SecurityFrameworkUtils.getLoginUserId())
+                        .eq(UserInfoAiDO::getInformationType, updateReqVO.getInformationType())
+                        .setSql("info_Status =0"));
+        updateReqVO.setInfoStatus("1");
+        updateReqVO.setTextInformation(AiFrameworkUtils.dataDual(updateReqVO.getInfoFiles()));
         UserInfoAiDO updateObj = BeanUtils.toBean(updateReqVO, UserInfoAiDO.class);
         userInfoAiMapper.updateById(updateObj);
     }