zrd 4 miesięcy temu
rodzic
commit
d6d397112d
15 zmienionych plików z 759 dodań i 2 usunięć
  1. 95 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/AppAiController.java
  2. 40 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/AppAiPromptManagementController.java
  3. 18 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/vo/WorkflowRunFileReqVO.java
  4. 42 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/vo/WorkflowRunPageReqVO.java
  5. 19 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/vo/WorkflowRunRespVO.java
  6. 25 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/vo/WorkflowRunSaveReqVO.java
  7. 8 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/AiPromptManagementService.java
  8. 5 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/AiPromptManagementServiceImpl.java
  9. 39 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/WorkflowRunService.java
  10. 175 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/WorkflowRunServiceImpl.java
  11. 68 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/utils/DifyFilesUtils.java
  12. 193 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/utils/DifyResponse.java
  13. 18 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/utils/FileResp.java
  14. 7 1
      yudao-server/src/main/resources/application-dev.yaml
  15. 7 1
      yudao-server/src/main/resources/application-local.yaml

+ 95 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/AppAiController.java

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.infra.controller.app.aipromptmanagement;
+
+import cn.hutool.core.io.FileUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.infra.controller.app.aipromptmanagement.vo.WorkflowRunFileReqVO;
+import cn.iocoder.yudao.module.infra.controller.app.aipromptmanagement.vo.WorkflowRunSaveReqVO;
+import cn.iocoder.yudao.module.infra.service.aipromptmanagement.WorkflowRunService;
+import cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils.DifyFilesUtils;
+import cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils.FileResp;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "APP - dify 工作流")
+@RestController
+@RequestMapping("/infra/ai-dify")
+@Validated
+public class AppAiController {
+    @Resource
+    private WorkflowRunService workflowRunService;
+    
+    public static File convert(MultipartFile multipartFile) throws IOException {
+        // 获取文件的原始文件名
+        String originalFilename = multipartFile.getOriginalFilename();
+        // 使用 Hutool 的 FileUtil 工具类创建临时文件
+        File tempFile = FileUtil.createTempFile(new File(originalFilename));
+        // 将 MultipartFile 中的内容复制到临时文件中
+        multipartFile.transferTo(tempFile);
+        return tempFile;
+    }
+    
+    @PostMapping("/getDifyResul")
+    @Operation(summary = "获取工作流结果")
+    public CommonResult<String> createChatConversationMy(@RequestBody WorkflowRunSaveReqVO createReqVO) {
+        
+        return success(workflowRunService.getDifyResul(createReqVO.getInputs(), createReqVO.getEventType()));
+    }
+    
+    
+    @PostMapping("/ocrResul")
+    @Operation(summary = "获取图片识别工作流结果")
+    public CommonResult<String> ocrResul(@RequestBody WorkflowRunSaveReqVO createReqVO) {
+        FileResp fileResp = workflowRunService.uploadFile(createReqVO.getFileUrl(), createReqVO.getEventType());
+        Map<String, Object> inputs = new HashMap<>();
+        inputs.put("images", DifyFilesUtils.getVariableValue(fileResp));
+        inputs.put("type", createReqVO.getEventType());
+        return success(workflowRunService.getDifyResul(inputs, createReqVO.getEventType()));
+    }
+    
+    /**
+     * 上传新文件
+     *
+     * @param files 文件
+     * @return {@link CommonResult }<{@link List }<{@link FileNewUploadReqVO }>>
+     * @throws Exception 例外
+     */
+    @PostMapping("/upload")
+    @Operation(summary = "上传文件")
+    public CommonResult<List<FileResp>> uploadNewFile(@RequestParam(value = "file", required = false) MultipartFile[] files) throws Exception {
+        List<FileResp> resList = new ArrayList<>();
+        for (MultipartFile file : files) {
+            
+            resList.add(workflowRunService.uploadFile(convert(file), "uploadNew"));
+        }
+        return success(resList);
+    }
+    
+    
+    /**
+     * 上传新文件
+     *
+     * @param files 文件
+     * @return {@link CommonResult }<{@link List }<{@link FileNewUploadReqVO }>>
+     * @throws Exception 例外
+     */
+    @PostMapping("/uploadByUrl")
+    @Operation(summary = "上传文件")
+    public CommonResult<FileResp> uploadNewFile(@RequestBody WorkflowRunFileReqVO files) {
+        
+        return success(workflowRunService.uploadFile(files.getUrl(), files.getEventType()));
+    }
+    
+}

+ 40 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/AppAiPromptManagementController.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.infra.controller.app.aipromptmanagement;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.infra.controller.admin.aipromptmanagement.vo.AiPromptManagementRespVO;
+import cn.iocoder.yudao.module.infra.dal.dataobject.aipromptmanagement.AiPromptManagementDO;
+import cn.iocoder.yudao.module.infra.service.aipromptmanagement.AiPromptManagementService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.annotation.security.PermitAll;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "APP - AI 提示词管理")
+@RestController
+@RequestMapping("/infra/ai-prompt-management")
+@Validated
+public class AppAiPromptManagementController {
+    
+    @Resource
+    private AiPromptManagementService aiPromptManagementService;
+    
+    
+    @GetMapping("/get")
+    @Operation(summary = "获得AI 提示词管理")
+    @Parameter(name = "title", description = "标题", required = true, example = "1024")
+    @PermitAll
+    public CommonResult<AiPromptManagementRespVO> getAiPromptManagement(@RequestParam("title") String title) {
+        AiPromptManagementDO aiPromptManagement = aiPromptManagementService.getAiPromptByTi(title);
+        return success(BeanUtils.toBean(aiPromptManagement, AiPromptManagementRespVO.class));
+    }
+    
+}

+ 18 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/vo/WorkflowRunFileReqVO.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.infra.controller.app.aipromptmanagement.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 工作流运行记录列表 Request VO")
+@Data
+public class WorkflowRunFileReqVO {
+    
+    @Schema(description = "输入参数 ")
+    private String url;
+    /**
+     * 事件类型
+     */
+    private String eventType;
+    
+    
+}

+ 42 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/vo/WorkflowRunPageReqVO.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.infra.controller.app.aipromptmanagement.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.io.Serial;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 工作流运行记录分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WorkflowRunPageReqVO extends PageParam {
+    
+    @Serial
+    private static final long serialVersionUID = 635537847448146344L;
+    @Schema(description = "输入参数 ")
+    private String inputs;
+    
+    @Schema(description = "响应模式(streaming/其他) ")
+    private String responseMode;
+    
+    @Schema(description = "用户标识 ")
+    private String user;
+    
+    @Schema(description = "Bearer认证令牌")
+    private String apiKey;
+    
+    @Schema(description = "执行状态(0未开始 1进行中 2已完成) ", example = "2")
+    private Integer status;
+    
+    @Schema(description = "创建时间")
+    
+    private LocalDateTime[] createTime;
+    
+    @Schema(description = "错误信息 ")
+    private String errorMsg;
+    
+}

+ 19 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/vo/WorkflowRunRespVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.infra.controller.app.aipromptmanagement.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.fhs.core.trans.vo.VO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 工作流运行记录 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WorkflowRunRespVO implements VO {
+    
+    private String id;
+    private String name;
+    private int size;
+    private String extension;
+    
+    
+}

+ 25 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/aipromptmanagement/vo/WorkflowRunSaveReqVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.infra.controller.app.aipromptmanagement.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Map;
+
+@Schema(description = "管理后台 - 工作流运行记录新增/修改 Request VO")
+@Data
+public class WorkflowRunSaveReqVO {
+    
+    /**
+     * 输入
+     */
+    Map<String, Object> inputs;
+    /**
+     * 事件类型
+     */
+    String eventType;
+    /**
+     * 文件url
+     */
+    String fileUrl;
+    
+}

+ 8 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/AiPromptManagementService.java

@@ -43,6 +43,14 @@ public interface AiPromptManagementService {
      */
     AiPromptManagementDO getAiPromptManagement(Long id);
     
+    /**
+     * 通过主题获取ai提示
+     *
+     * @param title 标题
+     * @return {@link AiPromptManagementDO }
+     */
+    AiPromptManagementDO getAiPromptByTi(String title);
+    
     /**
      * 获得AI 提示词管理分页
      *

+ 5 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/AiPromptManagementServiceImpl.java

@@ -62,6 +62,11 @@ public class AiPromptManagementServiceImpl implements AiPromptManagementService
         return aiPromptManagementMapper.selectById(id);
     }
     
+    @Override
+    public AiPromptManagementDO getAiPromptByTi(String title) {
+        return aiPromptManagementMapper.selectOne(AiPromptManagementDO::getTopic, title);
+    }
+    
     @Override
     public PageResult<AiPromptManagementDO> getAiPromptManagementPage(AiPromptManagementPageReqVO pageReqVO) {
         return aiPromptManagementMapper.selectPage(pageReqVO);

+ 39 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/WorkflowRunService.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.infra.service.aipromptmanagement;
+
+
+import cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils.FileResp;
+
+import java.io.File;
+import java.util.Map;
+
+/**
+ * 工作流运行记录 Service 接口
+ *
+ * @author 超级管理员
+ */
+public interface WorkflowRunService {
+    /**
+     * 上传文件
+     *
+     * @param url url
+     * @return {@link FileResp }
+     */
+    FileResp uploadFile(String url, String eventType);
+    
+    /**
+     * 上传文件
+     *
+     * @param url url
+     * @return {@link FileResp }
+     */
+    FileResp uploadFile(File file, String eventType);
+    
+    
+    /**
+     * 获取dify结果
+     *
+     * @param inputs 输入
+     * @return {@link String }
+     */
+    String getDifyResul(Map<String, Object> inputs, String eventType);
+}

+ 175 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/WorkflowRunServiceImpl.java

@@ -0,0 +1,175 @@
+package cn.iocoder.yudao.module.infra.service.aipromptmanagement;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.json.JSONObject;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils.DifyFilesUtils;
+import cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils.DifyResponse;
+import cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils.FileResp;
+import com.alibaba.fastjson.JSON;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.io.File;
+import java.util.Map;
+
+/**
+ * 工作流运行记录 Service 实现类
+ *
+ * @author 超级管理员
+ */
+@Service
+@Validated
+public class WorkflowRunServiceImpl implements WorkflowRunService {
+    
+    @Value("${dify.base-url}")
+    private String baseUrl;
+    
+    @Value("${dify.ocr-key}")
+    private String ocrKey;
+    @Value("${dify.file-path}")
+    private String filePath;
+    
+    /**
+     * 从 URL 中提取文件扩展名
+     *
+     * @param url URL 字符串
+     * @return 文件扩展名
+     */
+    public static String getFileExtension(String url) {
+        if (url == null || url.isEmpty()) {
+            return "";
+        }
+        
+        // 获取最后一个斜杠的位置
+        int lastSlashIndex = url.lastIndexOf('/');
+        if (lastSlashIndex == -1) {
+            return "";
+        }
+        
+        // 获取最后一个点的位置
+        int lastDotIndex = url.lastIndexOf('.');
+        if (lastDotIndex == -1 || lastDotIndex < lastSlashIndex) {
+            return "";
+        }
+        
+        // 提取文件扩展名
+        return "." + url.substring(lastDotIndex + 1);
+    }
+    
+    /**
+     * 上传文件
+     *
+     * @param file 文件
+     * @param user 用户
+     * @return {@link FileResp }
+     */
+    public FileResp uploadFileDify(File file, String user) {
+        FileResp fileResp = new FileResp();
+        // 接口地址
+        String url = baseUrl + "/v1/files/upload";
+        // 替换为你的实际 API Key
+        String apiKey = ocrKey;
+        
+        // 发送 POST 请求进行文件上传
+        HttpResponse response = HttpRequest.post(url)
+                .header("Authorization", "Bearer " + apiKey)
+                .form("file", file)
+                .form("user", user)
+                .execute();
+        
+        // 处理响应
+        if (response.isOk()) {
+            System.out.println("文件上传成功,响应内容:");
+            System.out.println(response.body());
+            fileResp = JSON.parseObject(response.body(), FileResp.class);
+        } else {
+            System.out.println("文件上传失败,状态码:" + response.getStatus());
+            System.out.println("错误信息:" + response.body());
+        }
+        return fileResp;
+    }
+    
+    /**
+     * 获取dify响应
+     *
+     * @param inputs 输入
+     * @param user   用户
+     * @return {@link DifyResponse }
+     */
+    public DifyResponse getDifyResponse(Map<String, Object> inputs, String user) {
+        DifyResponse difyResponse = new DifyResponse();
+        // 接口地址
+        String url = baseUrl + "/v1/workflows/run";
+        // 替换为你的实际 API Key
+        String apiKey = ocrKey;
+        
+        
+        // 创建一个 ObjectMapper 实例,用于处理 JSON 转换
+        
+        
+        // 构建请求体
+        JSONObject requestBody = new JSONObject();
+        requestBody.put("inputs", inputs);
+        requestBody.put("response_mode", "streaming");
+        requestBody.put("user", user);
+        
+        // 发送 POST 请求
+        HttpResponse response = HttpRequest.post(url)
+                .header("Authorization", "Bearer " + apiKey)
+                .header("Content-Type", "application/json")
+                .body(requestBody.toString())
+                .execute();
+        
+        
+        // 处理响应
+        if (response.isOk()) {
+            // Hutool工具示例
+            String decodedBody = Convert.unicodeToStr(response.body());
+            
+            // 使用 \n\n 分割字符串
+            String[] parts = decodedBody.split("\n\n");
+            
+            // 取最后一条内容
+            String lastPart = parts[parts.length - 1];
+            
+            System.out.println("请求成功,响应内容:");
+            System.out.println(lastPart);
+            // 去除"data: "前缀
+            String jsonStr = lastPart.substring(6);
+            
+            // 转换为DifyResponse实体
+            difyResponse = JSON.parseObject(jsonStr, DifyResponse.class);
+            System.out.println(difyResponse.getData().getOutputs().getText());
+        } else {
+            System.out.println("请求失败,状态码:" + response.getStatus());
+            System.out.println("错误信息:" + response.body());
+        }
+        return difyResponse;
+    }
+    
+    @Override
+    public FileResp uploadFile(String fileurl, String eventType) {
+        String extension = getFileExtension(fileurl);
+        
+        return uploadFileDify(DifyFilesUtils.downloadFile(fileurl, filePath +
+                IdUtil.fastSimpleUUID() + extension), SecurityFrameworkUtils.getLoginUserId().toString());
+    }
+    
+    @Override
+    public FileResp uploadFile(File file, String eventType) {
+        return uploadFileDify(file, SecurityFrameworkUtils.getLoginUserId().toString());
+    }
+    
+    @Override
+    public String getDifyResul(Map<String, Object> inputs, String eventType) {
+        // 创建 inputs 的 Map
+//        inputs.put("images", list);
+        DifyResponse response = getDifyResponse(inputs, SecurityFrameworkUtils.getLoginUserId().toString());
+        return response.getData().getOutputs().getOutput();
+    }
+}

+ 68 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/utils/DifyFilesUtils.java

@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * dify文件utils
+ *
+ * @author Administrator
+ * @date 2025/03/12
+ */
+public class DifyFilesUtils {
+    
+    private static final Logger logger = Logger.getLogger(DifyFilesUtils.class.getName());
+    
+    
+    /**
+     * 下载文件
+     *
+     * @param fileUrl 文件url
+     * @param saveDir 保存dir
+     * @return {@link File }
+     * @throws Exception 例外
+     */
+    public static File downloadFile(String fileUrl, String saveDir) {
+        File file = null;
+        try {
+            URL url = new URL(fileUrl);
+            try (InputStream is = url.openStream();
+                 FileOutputStream fos = new FileOutputStream(saveDir)) {
+                
+                byte[] buffer = new byte[1024];
+                int len;
+                while ((len = is.read(buffer)) != -1) {
+                    fos.write(buffer, 0, len);
+                }
+            }
+            file = new File(saveDir);
+        } catch (Exception e) {
+            logger.log(Level.SEVERE, "文件下载失败: " + e.getMessage(), e);
+        }
+        return file;
+    }
+    
+    
+    /**
+     * @param file
+     * @return {@link Map }<{@link String }, {@link Object }>
+     */
+    public static List<Map<String, Object>> getVariableValue(FileResp file) {
+        
+        // 创建内层的 Map 表示 "{variable_name}" 的值
+        Map<String, Object> variableValue = new HashMap<>();
+        variableValue.put("transfer_method", "local_file");
+        variableValue.put("upload_file_id", file.getId());
+        variableValue.put("type", "image");
+        
+        return List.of(variableValue);
+    }
+    
+}

+ 193 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/utils/DifyResponse.java

@@ -0,0 +1,193 @@
+package cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils;
+
+import java.util.List;
+
+public class DifyResponse {
+    
+    /**
+     * event : workflow_finished
+     * workflow_run_id : bad54afd-3650-4b24-86e6-c625fcc600cb
+     * task_id : 15712ca3-3350-4cd7-a0ad-c1d53350c9a5
+     * data : {"id":"bad54afd-3650-4b24-86e6-c625fcc600cb","workflow_id":"26b654ed-c5eb-498a-8f28-c303dcf3349b",
+     * "sequence_number":24,"status":"succeeded","outputs":{"text":"INSERT INTO `ruoyi-vue-pro`.`game_character_info`
+     * (player_name, level, combat_power, profession) VALUES('小杰', '8转216级', 40261, '道士'),('小沐沐', '8转200级', 30111,
+     * '法师'),('天命', '8转199级', 30384, '道士'),('司令', '8转197级', 24999, '法师'),('祖承泽', '7转185级', 21333, '法师'),('tx小道',
+     * '7转168级', 6792, '道士'),('S5563.神经侠侣', '8转188级', 21368, '法师'),('天~虎', '8转196级', 23122, '法师'),('王者', '7转174级',
+     * 15664, '战士'),('平凡爱人', '7转179级', 12249, '法师'),('没穿内裤', '8转225级', 49935, '法师'),('S5596.蜡笔小新', '8转187级', 22172,
+     * '法师'),('S5576.太阳的心', '7转183级', 19011, '法师');"},"error":null,"elapsed_time":16.629782980307937,
+     * "total_tokens":1773,"total_steps":4,"created_by":{"id":"8e1c763e-5dd2-4ccb-a633-eee77b10f9e9","user":"abc-123"
+     * },"created_at":1741768563,"finished_at":1741768580,"exceptions_count":0,"files":[]}
+     */
+    
+    private String event;
+    private String workflow_run_id;
+    private String task_id;
+    private DataBean data;
+    
+    // {"event": "workflow_finished", "workflow_run_id": "bad54afd-3650-4b24-86e6-c625fcc600cb", "task_id":
+    // "15712ca3-3350-4cd7-a0ad-c1d53350c9a5", "data": {"id": "bad54afd-3650-4b24-86e6-c625fcc600cb", "workflow_id":
+    // "26b654ed-c5eb-498a-8f28-c303dcf3349b", "sequence_number": 24, "status": "succeeded", "outputs": {"text":
+    // "INSERT INTO `ruoyi-vue-pro`.`game_character_info` (player_name, level, combat_power, profession) VALUES('小杰',
+    // '8转216级', 40261, '道士'),('小沐沐', '8转200级', 30111, '法师'),('天命', '8转199级', 30384, '道士'),('司令', '8转197级', 24999,
+    // '法师'),('祖承泽', '7转185级', 21333, '法师'),('tx小道', '7转168级', 6792, '道士'),('S5563.神经侠侣', '8转188级', 21368, '法师'),
+    // ('天~虎', '8转196级', 23122, '法师'),('王者', '7转174级', 15664, '战士'),('平凡爱人', '7转179级', 12249, '法师'),('没穿内裤',
+    // '8转225级', 49935, '法师'),('S5596.蜡笔小新', '8转187级', 22172, '法师'),('S5576.太阳的心', '7转183级', 19011, '法师');"},
+    // "error": null, "elapsed_time": 16.629782980307937, "total_tokens": 1773, "total_steps": 4, "created_by":
+    // {"id": "8e1c763e-5dd2-4ccb-a633-eee77b10f9e9", "user": "abc-123"}, "created_at": 1741768563, "finished_at":
+    // 1741768580, "exceptions_count": 0, "files": []}}
+    
+    public String getEvent() {return event;}
+    
+    public void setEvent(String event) {this.event = event;}
+    
+    public String getWorkflow_run_id() {return workflow_run_id;}
+    
+    public void setWorkflow_run_id(String workflow_run_id) {this.workflow_run_id = workflow_run_id;}
+    
+    public String getTask_id() {return task_id;}
+    
+    public void setTask_id(String task_id) {this.task_id = task_id;}
+    
+    public DataBean getData() {return data;}
+    
+    public void setData(DataBean data) {this.data = data;}
+    
+    public static class DataBean {
+        /**
+         * id : bad54afd-3650-4b24-86e6-c625fcc600cb
+         * workflow_id : 26b654ed-c5eb-498a-8f28-c303dcf3349b
+         * sequence_number : 24
+         * status : succeeded
+         * outputs : {"text":"INSERT INTO `ruoyi-vue-pro`.`game_character_info` (player_name, level, combat_power,
+         * profession) VALUES('小杰', '8转216级', 40261, '道士'),('小沐沐', '8转200级', 30111, '法师'),('天命', '8转199级', 30384,
+         * '道士'),('司令', '8转197级', 24999, '法师'),('祖承泽', '7转185级', 21333, '法师'),('tx小道', '7转168级', 6792, '道士'),('S5563
+         * .神经侠侣', '8转188级', 21368, '法师'),('天~虎', '8转196级', 23122, '法师'),('王者', '7转174级', 15664, '战士'),('平凡爱人',
+         * '7转179级', 12249, '法师'),('没穿内裤', '8转225级', 49935, '法师'),('S5596.蜡笔小新', '8转187级', 22172, '法师'),('S5576
+         * .太阳的心', '7转183级', 19011, '法师');"}
+         * error : null
+         * elapsed_time : 16.629782980307937
+         * total_tokens : 1773
+         * total_steps : 4
+         * created_by : {"id":"8e1c763e-5dd2-4ccb-a633-eee77b10f9e9","user":"abc-123"}
+         * created_at : 1741768563
+         * finished_at : 1741768580
+         * exceptions_count : 0
+         * files : []
+         */
+        
+        private String id;
+        private String workflow_id;
+        private int sequence_number;
+        private String status;
+        private OutputsBean outputs;
+        private Object error;
+        private double elapsed_time;
+        private int total_tokens;
+        private int total_steps;
+        private CreatedByBean created_by;
+        private int created_at;
+        private int finished_at;
+        private int exceptions_count;
+        private List<?> files;
+        
+        public String getId() {return id;}
+        
+        public void setId(String id) {this.id = id;}
+        
+        public String getWorkflow_id() {return workflow_id;}
+        
+        public void setWorkflow_id(String workflow_id) {this.workflow_id = workflow_id;}
+        
+        public int getSequence_number() {return sequence_number;}
+        
+        public void setSequence_number(int sequence_number) {this.sequence_number = sequence_number;}
+        
+        public String getStatus() {return status;}
+        
+        public void setStatus(String status) {this.status = status;}
+        
+        public OutputsBean getOutputs() {return outputs;}
+        
+        public void setOutputs(OutputsBean outputs) {this.outputs = outputs;}
+        
+        public Object getError() {return error;}
+        
+        public void setError(Object error) {this.error = error;}
+        
+        public double getElapsed_time() {return elapsed_time;}
+        
+        public void setElapsed_time(double elapsed_time) {this.elapsed_time = elapsed_time;}
+        
+        public int getTotal_tokens() {return total_tokens;}
+        
+        public void setTotal_tokens(int total_tokens) {this.total_tokens = total_tokens;}
+        
+        public int getTotal_steps() {return total_steps;}
+        
+        public void setTotal_steps(int total_steps) {this.total_steps = total_steps;}
+        
+        public CreatedByBean getCreated_by() {return created_by;}
+        
+        public void setCreated_by(CreatedByBean created_by) {this.created_by = created_by;}
+        
+        public int getCreated_at() {return created_at;}
+        
+        public void setCreated_at(int created_at) {this.created_at = created_at;}
+        
+        public int getFinished_at() {return finished_at;}
+        
+        public void setFinished_at(int finished_at) {this.finished_at = finished_at;}
+        
+        public int getExceptions_count() {return exceptions_count;}
+        
+        public void setExceptions_count(int exceptions_count) {this.exceptions_count = exceptions_count;}
+        
+        public List<?> getFiles() {return files;}
+        
+        public void setFiles(List<?> files) {this.files = files;}
+        
+        public static class OutputsBean {
+            /**
+             * text : INSERT INTO `ruoyi-vue-pro`.`game_character_info` (player_name, level, combat_power,
+             * profession) VALUES('小杰', '8转216级', 40261, '道士'),('小沐沐', '8转200级', 30111, '法师'),('天命', '8转199级', 30384,
+             * '道士'),('司令', '8转197级', 24999, '法师'),('祖承泽', '7转185级', 21333, '法师'),('tx小道', '7转168级', 6792, '道士'),
+             * ('S5563.神经侠侣', '8转188级', 21368, '法师'),('天~虎', '8转196级', 23122, '法师'),('王者', '7转174级', 15664, '战士'),
+             * ('平凡爱人', '7转179级', 12249, '法师'),('没穿内裤', '8转225级', 49935, '法师'),('S5596.蜡笔小新', '8转187级', 22172, '法师'),
+             * ('S5576.太阳的心', '7转183级', 19011, '法师');
+             */
+            
+            private String text;
+            private String output;
+            
+            public String getOutput() {
+                return output;
+            }
+            
+            public void setOutput(String output) {
+                this.output = output;
+            }
+            
+            public String getText() {return text;}
+            
+            public void setText(String text) {this.text = text;}
+        }
+        
+        public static class CreatedByBean {
+            /**
+             * id : 8e1c763e-5dd2-4ccb-a633-eee77b10f9e9
+             * user : abc-123
+             */
+            
+            private String id;
+            private String user;
+            
+            public String getId() {return id;}
+            
+            public void setId(String id) {this.id = id;}
+            
+            public String getUser() {return user;}
+            
+            public void setUser(String user) {this.user = user;}
+        }
+    }
+}

+ 18 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/aipromptmanagement/utils/FileResp.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.infra.service.aipromptmanagement.utils;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@Data
+public class FileResp {
+    
+    
+    private String id;
+    private String name;
+    private int size;
+    private String extension;
+    private String mime_type;
+    private String created_by;
+    private int created_at;
+}

+ 7 - 1
yudao-server/src/main/resources/application-dev.yaml

@@ -222,4 +222,10 @@ iot:
 
 # 插件配置
 pf4j:
-  pluginsDir: ${user.home}/plugins # 插件目录
+  pluginsDir: ${user.home}/plugins # 插件目录# 插件配置
+# dify 配置项
+dify:
+  base-url: http://42.194.163.46:9005/ # dify地址
+  ocr-key: app-LtIiXlum1GZjDhuhOqQXi6MG # 图片识别的key
+  asset-key: app-EsQ4vAwda8YhtosbDOefOZSA # 数据集登记的key
+  file-path: /home

+ 7 - 1
yudao-server/src/main/resources/application-local.yaml

@@ -269,4 +269,10 @@ justauth:
 --- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 ####################
 pf4j:
 #  pluginsDir: /tmp/
-  pluginsDir: ../plugins
+  pluginsDir: ../plugins
+
+dify:
+  base-url: http://42.194.163.46:9005/ # dify地址
+  ocr-key: app-LtIiXlum1GZjDhuhOqQXi6MG # 图片识别的key
+  asset-key: app-EsQ4vAwda8YhtosbDOefOZSA # 数据集登记的key
+  file-path: F:\wd\