diff --git a/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/constant/HwMomAiConstants.java b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/constant/HwMomAiConstants.java index c484cdf8..3d53be48 100644 --- a/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/constant/HwMomAiConstants.java +++ b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/constant/HwMomAiConstants.java @@ -12,4 +12,7 @@ public interface HwMomAiConstants { */ public static final String AI_DATABASE_SCHEMA_KEY_PREFIX = "ai:database:schema:"; + public static final String AI_FORM_SETTING_FIELD_TYPE_NORMAL = "1";//普通字段 + public static final String AI_FORM_SETTING_FIELD_TYPE_RELATE = "2";//关联表 + public static final String AI_FORM_SETTING_FIELD_TYPE_DICT = "3";//字典数据 } diff --git a/ruoyi-modules/hwmom-ai/pom.xml b/ruoyi-modules/hwmom-ai/pom.xml index c2fd184d..18f90f0b 100644 --- a/ruoyi-modules/hwmom-ai/pom.xml +++ b/ruoyi-modules/hwmom-ai/pom.xml @@ -83,6 +83,7 @@ ruoyi-common-translation + org.dromara ruoyi-common-sensitive @@ -111,12 +112,7 @@ com.microsoft.sqlserver mssql-jdbc - - org.dromara - hwmom-common-mom - 2.2.2 - compile - + org.dromara @@ -320,6 +316,22 @@ anyline-environment-spring-data-jdbc ${anyline.version} + + + + com.alibaba + dashscope-sdk-java + + 2.18.2 + + + + org.dromara + hwmom-common-mom + 2.2.2 + compile + + diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/HwMomAiApplication.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/HwMomAiApplication.java index 6070a063..e7bb2c56 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/HwMomAiApplication.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/HwMomAiApplication.java @@ -1,16 +1,14 @@ package org.dromara.ai; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.dromara.common.properties.MesProperties; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; -import org.springframework.boot.context.properties.EnableConfigurationProperties; /** - * 系统模块 + * AI模块 * - * @author ruoyi + * @author xins */ @EnableDubbo @SpringBootApplication diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/controller/AsrController.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/controller/AsrController.java new file mode 100644 index 00000000..70a9d902 --- /dev/null +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/controller/AsrController.java @@ -0,0 +1,90 @@ +package org.dromara.ai.asr.controller; + +import org.dromara.ai.asr.service.AliAsrService; +import org.dromara.common.core.domain.R; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +/** + * 语音识别控制器 + */ +@RestController +@RequestMapping("/asr") +public class AsrController { + + @Autowired + private AliAsrService aliAsrService; + +// /** +// * 语音识别接口 +// * @param audioFile 音频文件 +// * @return 识别结果 +// */ +// @PostMapping("/recognize") +// public ResponseEntity> recognizeSpeech(@RequestParam("audioFile") MultipartFile audioFile) { +// Map response = new HashMap<>(); +// +// try { +// if (audioFile.isEmpty()) { +// response.put("success", false); +// response.put("message", "请上传音频文件"); +// return ResponseEntity.badRequest().body(response); +// } +// +// // 调用语音识别服务 +// String result = aliAsrService.recognizeSpeech(audioFile); +// +// response.put("success", true); +// response.put("result", result); +// return ResponseEntity.ok(response); +// +// } catch (Exception e) { +// response.put("success", false); +// response.put("message", "识别过程中发生错误: " + e.getMessage()); +// return ResponseEntity.status(500).body(response); +// } +// } + + + /** + * 通过URL进行语音识别(用于测试或特定场景) + */ + @PostMapping("/recognizeSpeechByUrl") + public R> recognizeSpeechByUrl( + @RequestParam("audioUrl") String audioUrl) { + + Map response = new HashMap<>(); + + try { + if (audioUrl == null || audioUrl.trim().isEmpty()) { + response.put("success", false); + response.put("message", "请提供音频文件URL"); + return R.ok(response); + } + + System.out.println("接收到音频文件URL: {"+audioUrl+"}"); + + String resultText = aliAsrService.recognizeSpeechByUrl(audioUrl); + + response.put("success", true); + response.put("text", resultText); + response.put("message", "语音识别成功"); + + return R.ok(response); + + } catch (Exception e) { + e.printStackTrace(); + response.put("success", false); + response.put("message", "语音识别失败: " + e.getMessage()); + throw new RuntimeException("语音识别失败: " + e.getMessage()); +// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + +} diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/service/AliAsrService.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/service/AliAsrService.java new file mode 100644 index 00000000..a2aa529f --- /dev/null +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/service/AliAsrService.java @@ -0,0 +1,23 @@ +package org.dromara.ai.asr.service; + +/** + * @Author xins + * @Date 2025/9/19 15:50 + * @Description: + */ +public interface AliAsrService { + /** + * 识别音频文件中的语音内容 + * @param audioFile 音频文件 + * @return 识别结果文本 + */ +// String recognizeSpeech(MultipartFile audioFile); + + /** + * 通过URL识别音频文件中的语音内容 + * @param audioUrl 音频文件URL + * @return 识别结果文本 + */ + String recognizeSpeechByUrl(String audioUrl); + +} diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/service/AliAsrServiceImpl.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/service/AliAsrServiceImpl.java new file mode 100644 index 00000000..e4b8e25d --- /dev/null +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/asr/service/AliAsrServiceImpl.java @@ -0,0 +1,175 @@ +package org.dromara.ai.asr.service; + +import com.alibaba.dashscope.audio.asr.transcription.Transcription; +import com.alibaba.dashscope.audio.asr.transcription.TranscriptionParam; +import com.alibaba.dashscope.audio.asr.transcription.TranscriptionQueryParam; +import com.alibaba.dashscope.audio.asr.transcription.TranscriptionResult; +import com.alibaba.dashscope.audio.asr.transcription.TranscriptionTaskResult; +import com.alibaba.dashscope.common.TaskStatus; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Arrays; +import java.util.List; + +/** + * 阿里云语音识别服务实现类 + */ +@Service +public class AliAsrServiceImpl implements AliAsrService { + + private static final Logger logger = LoggerFactory.getLogger(AliAsrServiceImpl.class); + + // 从配置文件读取API Key +// @Value("${aliyun.asr.api-key}") + private String apiKey = "sk-ce77518fcbc54b2bbee2a7c793be6492"; + + // 临时文件存储路径 +// @Value("${file.upload.temp-dir}") +// private String tempDir; + + // 模型名称 + private static final String MODEL_NAME = "sensevoice-v1"; + + // 语言提示 + private static final String[] LANGUAGE_HINTS = {"zh"}; + +// @Override +// public String recognizeSpeech(MultipartFile audioFile) { +// try { +// // 保存上传的文件到临时目录 +// String fileName = UUID.randomUUID().toString() + getFileExtension(audioFile.getOriginalFilename()); +// File tempFile = new File(tempDir, fileName); +// FileUtils.copyInputStreamToFile(audioFile.getInputStream(), tempFile); +// +// try { +// // 这里应该上传文件到可公开访问的存储服务,然后获取URL +// // 为简化示例,这里假设文件已上传到可访问的URL +// String audioUrl = "http://example.com/temp/" + fileName; +// +// // 调用URL方式进行识别 +// return recognizeSpeechByUrl(audioUrl); +// } finally { +// // 清理临时文件 +// FileUtils.deleteQuietly(tempFile); +// } +// } catch (IOException e) { +// logger.error("处理音频文件失败", e); +// throw new RuntimeException("处理音频文件失败: " + e.getMessage()); +// } +// } + + @Override + public String recognizeSpeechByUrl(String audioUrl) { + try { + // 构建识别参数 + TranscriptionParam param = TranscriptionParam.builder() + .apiKey(apiKey) + .model(MODEL_NAME) + .fileUrls(Arrays.asList(audioUrl)) + .parameter("language_hints", LANGUAGE_HINTS) + .build(); + + Transcription transcription = new Transcription(); + + // 提交语音识别任务 + TranscriptionResult result = transcription.asyncCall(param); + String taskId = result.getTaskId(); + logger.info("语音识别任务提交成功,TaskId: {}", taskId); + + // 循环获取任务执行结果,直到任务结束 + while (true) { + result = transcription.fetch(TranscriptionQueryParam.FromTranscriptionParam(param, taskId)); + + if (result.getTaskStatus() == TaskStatus.SUCCEEDED) { + logger.info("语音识别任务完成,TaskId: {}", taskId); + break; + } else if (result.getTaskStatus() == TaskStatus.FAILED) { + logger.error("语音识别任务失败,TaskId: {}, 错误信息: {}", taskId, result.getResults().toString()); + throw new RuntimeException("语音识别任务失败: " + result.getResults().toString()); + } + + // 等待1秒后再次查询 + Thread.sleep(1000); + } + + // 解析识别结果 + return parseRecognitionResult(result); + + } catch (Exception e) { + logger.error("语音识别过程发生错误", e); + throw new RuntimeException("语音识别失败: " + e.getMessage()); + } + } + + /** + * 解析识别结果 + */ + private String parseRecognitionResult(TranscriptionResult result) throws Exception { + List taskResultList = result.getResults(); + if (taskResultList == null || taskResultList.isEmpty()) { + throw new RuntimeException("未获取到识别结果"); + } + + TranscriptionTaskResult taskResult = taskResultList.get(0); + String transcriptionUrl = taskResult.getTranscriptionUrl(); + + // 获取识别结果详情 + HttpURLConnection connection = (HttpURLConnection) new URL(transcriptionUrl).openConnection(); + connection.setRequestMethod("GET"); + connection.connect(); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + JsonElement jsonElement = gson.fromJson(reader, JsonElement.class); + + if (jsonElement.isJsonObject()) { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + JsonArray transcriptsArr = jsonObject.getAsJsonArray("transcripts"); + + if (transcriptsArr != null && !transcriptsArr.isEmpty()) { + JsonObject jsonObject1 = transcriptsArr.get(0).getAsJsonObject(); + String text = jsonObject1.get("text").getAsString(); + return extractTextFromTags(text); + } + } + + throw new RuntimeException("解析识别结果失败"); + } finally { + connection.disconnect(); + } + } + + /** + * 从文本中提取纯文本内容(移除标签) + */ + private String extractTextFromTags(String text) { + if (text == null || text.trim().isEmpty()) { + return ""; + } + // 移除所有类似<...>或[...]的标签 + return text.replaceAll("<[^>]+>", "") + .replaceAll("\\[[^]]+]", "") + .trim(); + } + + /** + * 获取文件扩展名 + */ + private String getFileExtension(String fileName) { + if (fileName == null || !fileName.contains(".")) { + return ".wav"; // 默认使用wav格式 + } + return fileName.substring(fileName.lastIndexOf('.')); + } +} diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/controller/AiAssistantController.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/controller/AiAssistantController.java index ab8ce136..9397c17c 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/controller/AiAssistantController.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/controller/AiAssistantController.java @@ -7,6 +7,7 @@ package org.dromara.ai.controller; */ import cn.dev33.satoken.annotation.SaCheckPermission; +import com.alibaba.fastjson.JSONObject; import jakarta.validation.constraints.NotEmpty; import lombok.RequiredArgsConstructor; import org.dromara.ai.domain.bo.AiChatMessageBo; @@ -14,6 +15,7 @@ import org.dromara.ai.domain.bo.AiChatMessageTopicBo; import org.dromara.ai.domain.bo.AiModelBo; import org.dromara.ai.domain.vo.AiChatMessageVo; import org.dromara.ai.domain.vo.AiModelVo; +import org.dromara.ai.process.dto.AIFillFormRequest; import org.dromara.ai.test.vectorization.factory.EmbeddingServiceFactory; import org.dromara.ai.test.vectorization.process.IEmbeddingProcessor; import org.dromara.ai.process.dto.AIMessage; @@ -132,7 +134,8 @@ public class AiAssistantController extends BaseController { /** - * 根绝用户输入生成sql,传入参数包括用户输入、AIModelID, AIPLATFORMID + * 根据用户输入生成sql,传入参数包括用户输入、AIModelID, AIPLATFORMID + * * @param request * @return */ @@ -142,7 +145,21 @@ public class AiAssistantController extends BaseController { } + /** + * 根据用户输入获得智能表单填报数据,传入参数包括用户输入 + * + * @param aiFillFormRequest + * @return + */ + @PostMapping(value = "/aiFillForm") + public JSONObject aiFillForm(@Validated(EditGroup.class) @RequestBody AIFillFormRequest aiFillFormRequest) { + try { + return aiAssistantService.aiFillForm(aiFillFormRequest); + } catch (Exception e) { + throw new RuntimeException("请重试:" + e.getMessage()); + } + } // /** @@ -158,8 +175,4 @@ public class AiAssistantController extends BaseController { // } - - - - } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/controller/AiFormSettingController.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/controller/AiFormSettingController.java index 6d44ef58..7bed8a42 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/controller/AiFormSettingController.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/controller/AiFormSettingController.java @@ -8,6 +8,7 @@ import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; import org.dromara.ai.domain.AiFormSetting; import org.dromara.ai.domain.AiSqlTable; +import org.dromara.ai.domain.bo.AiFormSettingDetailBo; import org.dromara.ai.domain.bo.AiSqlTableBo; import org.dromara.ai.domain.vo.AiFormSettingDetailVo; import org.dromara.common.mybatis.helper.DataBaseHelper; @@ -150,5 +151,15 @@ public class AiFormSettingController extends BaseController { aiFormSettingBo.getDataName())); } + /** + * 下拉框查询AI表单设置属性详情列表 + */ + + @GetMapping("/getAiFormSettingDetailList") + public R> getAiFormSettingDetailList(AiFormSettingDetailBo bo) { + List list = aiFormSettingService.selectFormSettingDetailList(bo); + return R.ok(list); + } + } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/AiFormSetting.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/AiFormSetting.java index 3d3cba60..45a5baab 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/AiFormSetting.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/AiFormSetting.java @@ -1,5 +1,6 @@ package org.dromara.ai.domain; +import com.alibaba.excel.annotation.ExcelProperty; import org.dromara.common.tenant.core.TenantEntity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; @@ -54,6 +55,11 @@ public class AiFormSetting extends TenantEntity { */ private String formName; + /** + * 表单加载类型(1表单(直接加载表单),2菜单(打开菜单弹窗)) + */ + private String formLoadType; + /** * 表单路径(与sys_menu中的component一样,例如/mes/info/index) */ diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/AiFormSettingDetail.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/AiFormSettingDetail.java index 229a235b..3d5ba715 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/AiFormSettingDetail.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/AiFormSettingDetail.java @@ -1,5 +1,8 @@ package org.dromara.ai.domain; +import jakarta.validation.constraints.NotBlank; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; import org.dromara.common.mybatis.core.domain.BaseEntity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; @@ -58,4 +61,39 @@ public class AiFormSettingDetail { private String settingFlag; + /** + * 字段类型(1普通字段,2关联表,3字典数据) + */ + private String fieldType; + + /** + * 关联表名称 + */ + private String relateTableName; + + /** + * 关联表描述 + */ + private String relateTableDesc; + + /** + * 关联表字段,例如{fieldName:'dept_name',formProp:'deptName',fieldType:'2'}] + */ + private String relateTableFields; + + + /** + * 关联表SQL语句实例 + */ + private String sqlSample; + + /** + * 字段样式(1普通输入框,2下拉列表框,3弹出选择) + */ + private String fieldStyle; + + /** + *关联表数据过滤条件(例如:[{fieldKey:'delFlag',fieldValue:'0',conditionSymbol:'='}]) + */ + private String relateFilterCondition; } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/bo/AiFormSettingBo.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/bo/AiFormSettingBo.java index 2dabc74a..9204e040 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/bo/AiFormSettingBo.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/bo/AiFormSettingBo.java @@ -57,6 +57,12 @@ public class AiFormSettingBo extends BaseEntity { @NotBlank(message = "表单名称不能为空", groups = { AddGroup.class, EditGroup.class }) private String formName; + /** + * 表单加载类型(1表单(直接加载表单),2菜单(打开菜单弹窗)) + */ + @NotBlank(message = "表单加载类型(1表单(直接加载表单),2菜单(打开菜单弹窗))不能为空", groups = { AddGroup.class, EditGroup.class }) + private String formLoadType; + /** * 表单路径(与sys_menu中的component一样,例如/mes/info/index) */ diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/bo/AiFormSettingDetailBo.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/bo/AiFormSettingDetailBo.java index dcc98c36..650e9d5c 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/bo/AiFormSettingDetailBo.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/bo/AiFormSettingDetailBo.java @@ -63,4 +63,40 @@ public class AiFormSettingDetailBo extends BaseEntity { private String settingFlag; + /** + * 字段类型(1普通字段,2关联表,3字典数据) + */ + @NotBlank(message = "字段类型(1普通字段,2关联表,3字典数据)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String fieldType; + + /** + * 关联表名称 + */ + private String relateTableName; + + /** + * 关联表描述 + */ + private String relateTableDesc; + + /** + * 关联表字段,例如dept_id as deptId,dept_name as deptName + */ + private String relateTableFields; + + /** + * 关联表SQL语句实例 + */ + private String sqlSample; + + /** + * 字段样式(1普通输入框,2下拉列表框,3弹出选择) + */ + @NotBlank(message = "字段样式(1普通输入框,2下拉列表框,3弹出选择)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String fieldStyle; + + /** + *关联表数据过滤条件(例如:[{fieldKey:'delFlag',fieldValue:'0',conditionSymbol:'='}]) + */ + private String relateFilterCondition; } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableConditionWrapper.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableConditionWrapper.java new file mode 100644 index 00000000..4dcc0d39 --- /dev/null +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableConditionWrapper.java @@ -0,0 +1,15 @@ +package org.dromara.ai.domain.dto; + +/** + * @Author xins + * @Date 2025/9/25 8:50 + * @Description:创建一个包装类来包含条件列表,便于在MyBatis中传递 + */ + +import lombok.Data; +import java.util.List; + +@Data +public class AiTableConditionWrapper { + private List aiTableQueryConditions; +} diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableData.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableData.java new file mode 100644 index 00000000..955bca53 --- /dev/null +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableData.java @@ -0,0 +1,32 @@ +package org.dromara.ai.domain.dto; + +/** + * @description AiSqlTable Delete dto + * @author xins + * @date 2025/9/5 14:50 + */ + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.EditGroup; + +@Data +public class AiTableData { + /** + * 表字段key + */ + private String fieldKey; + + /** + * 表字段名称 + */ + private Object fieldValue; + + /** + * 表字段类型 + */ + private String fieldType; + +} + diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableQueryCondition.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableQueryCondition.java new file mode 100644 index 00000000..b1bc9610 --- /dev/null +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/dto/AiTableQueryCondition.java @@ -0,0 +1,15 @@ +package org.dromara.ai.domain.dto; + +import lombok.Data; + +/** + * @description 获取AiForSettingDetail关联表的查询条件封装dto + * @author xins + * @date 2025/9/25 8:51 + */ +@Data +public class AiTableQueryCondition { + private String fieldKey; + private String fieldValue; + private String conditionSymbol; +} diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/vo/AiFormSettingDetailVo.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/vo/AiFormSettingDetailVo.java index 36f95a43..006d6a58 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/vo/AiFormSettingDetailVo.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/vo/AiFormSettingDetailVo.java @@ -1,8 +1,11 @@ package org.dromara.ai.domain.vo; +import jakarta.validation.constraints.NotBlank; import org.dromara.ai.domain.AiFormSettingDetail; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; import org.dromara.common.excel.annotation.ExcelDictFormat; import org.dromara.common.excel.convert.ExcelDictConvert; import io.github.linpeilie.annotations.AutoMapper; @@ -73,4 +76,39 @@ public class AiFormSettingDetailVo implements Serializable { private String settingFlag; + /** + * 字段类型(1普通字段,2关联表,3字典数据) + */ + private String fieldType; + + /** + * 关联表名称 + */ + private String relateTableName; + + /** + * 关联表描述 + */ + private String relateTableDesc; + + /** + * 关联表字段,例如dept_id as deptId,dept_name as deptName + */ + private String relateTableFields; + + /** + * 关联表SQL语句实例 + */ + private String sqlSample; + + /** + * 字段样式(1普通输入框,2下拉列表框,3弹出选择) + */ + private String fieldStyle; + + /** + *关联表数据过滤条件(例如:[{fieldKey:'delFlag',fieldValue:'0',conditionSymbol:'='}]) + */ + private String relateFilterCondition; + } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/vo/AiFormSettingVo.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/vo/AiFormSettingVo.java index 400d181b..c743f02c 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/vo/AiFormSettingVo.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/domain/vo/AiFormSettingVo.java @@ -1,9 +1,13 @@ package org.dromara.ai.domain.vo; +import com.baomidou.mybatisplus.annotation.TableField; +import jakarta.validation.constraints.NotBlank; import org.dromara.ai.domain.AiFormSetting; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import org.dromara.ai.domain.AiFormSettingDetail; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; import org.dromara.common.excel.annotation.ExcelDictFormat; import org.dromara.common.excel.convert.ExcelDictConvert; import io.github.linpeilie.annotations.AutoMapper; @@ -65,6 +69,13 @@ public class AiFormSettingVo implements Serializable { @ExcelProperty(value = "表单名称") private String formName; + + /** + * 表单加载类型(1表单(直接加载表单),2菜单(打开菜单弹窗)) + */ + @ExcelProperty(value = "表单加载类型(1表单(直接加载表单),2菜单(打开菜单弹窗))不能为空") + private String formLoadType; + /** * 表单路径(与sys_menu中的component一样,例如/mes/info/index) */ diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/knowledge/parsing/MarkdownFileParsing.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/knowledge/parsing/MarkdownFileParsing.java new file mode 100644 index 00000000..ab436905 --- /dev/null +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/knowledge/parsing/MarkdownFileParsing.java @@ -0,0 +1,55 @@ +package org.dromara.ai.knowledge.parsing; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.ai.knowledge.parsing.enums.FileTypeEnum; +import org.dromara.ai.knowledge.split.CharacterTextSplitter; +import org.dromara.ai.knowledge.split.ITextSplitter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; + +/** + * @Author xins + * @Date 2025/8/19 11:10 + * @Description: + */ +@Component +@Slf4j +public class MarkdownFileParsing implements IFileParsing{ + private final ITextSplitter textSplitter; + + public MarkdownFileParsing() { + this.textSplitter = new CharacterTextSplitter(); + } + + @Override + public String getFileContent(InputStream inputStream) { + StringBuffer stringBuffer = new StringBuffer(); + try (InputStreamReader reader = new InputStreamReader(inputStream); + BufferedReader bufferedReader = new BufferedReader(reader)){ + String line; + while ((line = bufferedReader.readLine()) != null) { + stringBuffer.append(line).append("\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } + return stringBuffer.toString(); + } + + @Override + public List getContentChunkList(String content, String knowledgeBaseSeparator, int textBlockSize, int overlapChar) { + return textSplitter.splitContent(content, knowledgeBaseSeparator,textBlockSize,overlapChar); + } + + @Override + public FileTypeEnum supportedFileType() { + return FileTypeEnum.MD; + } +} diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/mapper/SQLServerDatabaseMetaMapper.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/mapper/SQLServerDatabaseMetaMapper.java index 848b16cd..f3c197f6 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/mapper/SQLServerDatabaseMetaMapper.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/mapper/SQLServerDatabaseMetaMapper.java @@ -1,9 +1,11 @@ package org.dromara.ai.mapper; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; +import org.dromara.ai.domain.dto.AiTableConditionWrapper; import java.util.List; import java.util.Map; @@ -44,4 +46,22 @@ public interface SQLServerDatabaseMetaMapper { List> getTablesStructureByTableNames(@Param("tableNames") String[] tableNames); + + + /** + * 完整的动态SELECT查询 + * @param tableName 表名 + * @param fields 查询字段列表(为空时查询所有字段) + * @param conditions 查询条件 + * @param orderBy 排序字段 + * @param groupBy 分组字段 + * @return 查询结果 + */ + List> dynamicSelect(@Param("tableName") String tableName, + @Param("fields") List fields, + @Param("conditions") Map conditions, + @Param("wrapper") AiTableConditionWrapper wrapper, + @Param("orderBy") String orderBy, + @Param("groupBy") String groupBy); + } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/process/dto/AIFillFormRequest.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/process/dto/AIFillFormRequest.java new file mode 100644 index 00000000..2f04988b --- /dev/null +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/process/dto/AIFillFormRequest.java @@ -0,0 +1,45 @@ +package org.dromara.ai.process.dto; + +/** + * @description AI request dto 聊天请求参数 + * @author xins + * @date 2025/7/29 14:44 + */ + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.ai.domain.AiFormSettingDetail; +import org.dromara.ai.process.enums.AIProviderEnum; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; + +import java.util.List; + +@Data +public class AIFillFormRequest { + + /** + * AI表单设置ID + */ + @NotNull(message = "AI表单设置ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long formSettingId; + + /** + * 用户提问内容 + */ + @NotNull(message = "用户提问内容不能为空", groups = { AddGroup.class, EditGroup.class }) + private String naturalLanguageQuery; + + /** + * AI表单设置属性详情列表 + */ + @NotNull(message = "AI表单设置属性详情列表不能为空", groups = { AddGroup.class, EditGroup.class }) + private List formSettingDetailList; + + /** + * 其他自定义参数 + */ + private Object customParams; +} diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/IAIAssistantService.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/IAIAssistantService.java index 139b96fa..3b30c856 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/IAIAssistantService.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/IAIAssistantService.java @@ -1,5 +1,7 @@ package org.dromara.ai.service; +import com.alibaba.fastjson.JSONObject; +import org.dromara.ai.process.dto.AIFillFormRequest; import org.dromara.ai.process.dto.AIRequest; import org.dromara.ai.process.dto.AIResponse; import reactor.core.publisher.Flux; @@ -23,5 +25,12 @@ public interface IAIAssistantService { public String generateSQL(AIRequest aiRequest); + /** + * ai智能表单填报 + * + * @param aiFillFormRequest + * @return String + */ + public JSONObject aiFillForm(AIFillFormRequest aiFillFormRequest); // public boolean testAIModel(String provider, AIRequest aiRequest); } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/IAiFormSettingService.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/IAiFormSettingService.java index 87e5d048..5235179e 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/IAiFormSettingService.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/IAiFormSettingService.java @@ -2,6 +2,7 @@ package org.dromara.ai.service; import com.baomidou.dynamic.datasource.annotation.DS; import org.dromara.ai.domain.AiFormSetting; +import org.dromara.ai.domain.bo.AiFormSettingDetailBo; import org.dromara.ai.domain.vo.AiFormSettingDetailVo; import org.dromara.ai.domain.vo.AiFormSettingVo; import org.dromara.ai.domain.bo.AiFormSettingBo; @@ -87,4 +88,11 @@ public interface IAiFormSettingService { * @return 列信息 */ public List selectDbTableColumnsByName(String tableName, String dataName); + + /** + * 获取AI表单设置属性列表 + * @param aiFormSettingDetailBo + * @return + */ + public List selectFormSettingDetailList(AiFormSettingDetailBo aiFormSettingDetailBo); } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AIAssistantServiceImpl.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AIAssistantServiceImpl.java index 1b9b65b7..29270da2 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AIAssistantServiceImpl.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AIAssistantServiceImpl.java @@ -1,13 +1,18 @@ package org.dromara.ai.service.impl; import com.alibaba.excel.util.StringUtils; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.core.JsonProcessingException; +import org.dromara.ai.domain.AiFormSettingDetail; import org.dromara.ai.domain.AiModel; -import org.dromara.ai.domain.vo.AiModelVo; +import org.dromara.ai.domain.dto.AiTableConditionWrapper; +import org.dromara.ai.domain.dto.AiTableData; +import org.dromara.ai.domain.dto.AiTableQueryCondition; import org.dromara.ai.mapper.AiModelMapper; +import org.dromara.ai.process.dto.AIFillFormRequest; import org.dromara.ai.process.dto.AIResponse; -import org.dromara.ai.test.ChatRequest; import org.dromara.ai.mapper.SQLServerDatabaseMetaMapper; import org.dromara.ai.process.dto.AIMessage; import org.dromara.ai.process.dto.AIRequest; @@ -43,9 +48,6 @@ public class AIAssistantServiceImpl implements IAIAssistantService { @Autowired private AiModelMapper aiModelMapper; - @Autowired - private Map aiProviderProcessorMap; - @Autowired private AIProviderProcessorFactory aiProviderProcessorFactory; @@ -58,6 +60,9 @@ public class AIAssistantServiceImpl implements IAIAssistantService { @Autowired private StringRedisTemplate redisTemplate; + @Autowired + private SQLServerDatabaseMetaMapper sQLServerDatabaseMetaMapper; + /** * 流式聊天接口 * @@ -365,7 +370,191 @@ public class AIAssistantServiceImpl implements IAIAssistantService { } -// /** + /** + * ai智能表单填报 + * + * @param aiFillFormRequest + * @return String + */ + @Override + public JSONObject aiFillForm(AIFillFormRequest aiFillFormRequest) { + +// List fields = Arrays.asList("dept_id as deptId", "dept_name as deptName"); +// Map condition = new HashMap<>(); +// condition.put("dept_name", "测试"); +// List> tableData = sQLServerDatabaseMetaMapper.dynamicSelect("sys_dept", fields, condition, "", ""); +// +// if (tableData != null) { +// return ""; +// } + + + String naturalLanguageQuery = aiFillFormRequest.getNaturalLanguageQuery(); + List aiFormSettingDetailList = aiFillFormRequest.getFormSettingDetailList(); + StringBuilder sb = new StringBuilder("你是一个智能表单填充助手。请根据我的要求、提供的数据库表字段信息,生成一份用于直接填充Vue3前端表单的JSON数据。\n\n"); + + sb.append("【要求】\n"); + sb.append(naturalLanguageQuery).append(",\n\n"); + + sb.append("【数据库表信息】\n"); + sb.append(getFormattedFormSettingDetails(aiFormSettingDetailList)); + + sb.append("\n【输出要求】\n"); + sb.append("1. 请根据我的核心要求,智能推断并填充所有相关字段的值\n"); + sb.append("2. 生成一个纯净的JSON对象,不要任何额外的解释、文本或markdown代码块标记,键是字段名,值是根据我的要求推断出来的值\n"); +// sb.append("3. 请返回**纯净的JSON格式**数据,不要任何额外的解释、文本或markdown代码块标记\n"); + sb.append("3. 仅返回一个JSON对象,不要返回JSON数组,不要返回任何测试数据和推测的数据\n"); + sb.append("4. 其他没有要求返回的数据返回空字符串\n"); + + IUnifiedAIProviderProcessor processor = aiProviderProcessorFactory.getProcessorByPlatformId(1L); + AIMessage aiMessage = new AIMessage(); + aiMessage.setRole("user"); + aiMessage.setContent(sb.toString()); + + AIRequest aiRequest = new AIRequest(); + aiRequest.setMessages(Collections.singletonList(aiMessage)); + aiRequest.setModelId(1L); + + Mono response = processor.chat(aiRequest); + if (Objects.requireNonNull(response.block()).isSuccess()) { + String content = response.block().getContent().toString(); + JSONObject contentJson = JSONObject.parseObject(content); + parseRelateTable(aiFormSettingDetailList, contentJson); + System.out.println(contentJson.toJSONString()); + return contentJson; + + } else { + throw new RuntimeException("生成sql语句失败" + response.block().getErrorMessage()); + } + + } + + private void parseRelateTable(List aiFormSettingDetailList, JSONObject contentJson) { + for (AiFormSettingDetail aiFormSettingDetail : aiFormSettingDetailList) { + if (aiFormSettingDetail.getSettingFlag().equals("1")) { + String fieldType = StringUtils.isBlank(aiFormSettingDetail.getFieldType()) ? HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_NORMAL : aiFormSettingDetail.getFieldType(); + String relateTableName = aiFormSettingDetail.getRelateTableName(); + String relateTableFields = aiFormSettingDetail.getRelateTableFields(); + if (fieldType.equals(HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_RELATE) && + StringUtils.isNotBlank(relateTableName) && StringUtils.isNotBlank(relateTableFields)) { + Object value = contentJson.get(aiFormSettingDetail.getFormProp()); + if (value != null && value instanceof JSONArray) { + JSONArray valueArr = (JSONArray) value; + if (valueArr.size() > 0) { + JSONObject conditionJson = valueArr.getJSONObject(0); + Set conditionKeys = conditionJson.keySet(); + Map conditionMap = new HashMap<>(); + for (String conditionKey : conditionKeys) { + conditionMap.put(camelToSnakeEnhanced(conditionKey), conditionJson.get(conditionKey)); + } + + JSONArray relateTableFieldArr = JSONArray.parseArray(relateTableFields); + +// List relateTableFieldList = Arrays.asList(relateTableFields.split(",")); + List relateTableFieldList = relateTableFieldArr.stream() + .map(obj -> { + JSONObject jsonObj = (JSONObject) obj; + return jsonObj.getString("fieldName") + " as " + jsonObj.getString("formProp"); + }) + .collect(Collectors.toList()); + + String relateFilterCondition = aiFormSettingDetail.getRelateFilterCondition(); + //[{fieldKey:'del_flag',fieldValue:'0',conditionSymbol:'='}] + // 创建条件包装类 + AiTableConditionWrapper wrapper = new AiTableConditionWrapper(); + if(StringUtils.isNotBlank(relateFilterCondition)){ + // 解析JSON字符串为条件列表 + List conditions = JSON.parseArray(relateFilterCondition, AiTableQueryCondition.class); + wrapper.setAiTableQueryConditions(conditions); +// JSONArray relateFilterConditionArr = JSONArray.parseArray(relateFilterCondition); + + } + + List> tableData = sQLServerDatabaseMetaMapper.dynamicSelect(relateTableName, relateTableFieldList, conditionMap, wrapper,"", ""); + JSONArray relateTableDataArr = new JSONArray(); + for (Map tableD : tableData) { +// JSONObject tableDataJson = new JSONObject(); + JSONArray tableFiledDataArr = new JSONArray(); + +// tableDataJson.put("relateTableDesc",aiFormSettingDetail.getRelateTableDesc()); + AiTableData aiTableData = new AiTableData(); + aiTableData.setFieldKey("relateTableDesc"); + aiTableData.setFieldValue(aiFormSettingDetail.getRelateTableDesc()); + aiTableData.setFieldType("3");//在选择时显示的title + tableFiledDataArr.add(aiTableData); + Set tableDataKeys = tableD.keySet(); + for (String tableDataKey : tableDataKeys) { +// tableDataJson.put(tableDataKey,tableD.get(tableDataKey)); + + aiTableData = new AiTableData(); + if (tableDataKey.contains("Id")) { + aiTableData.setFieldType("1");//主键,赋值使用 + } else { + aiTableData.setFieldType("2");//显示使用 + } + + aiTableData.setFieldKey(tableDataKey); + aiTableData.setFieldValue(tableD.get(tableDataKey)); + + tableFiledDataArr.add(aiTableData); + } + + relateTableDataArr.add(tableFiledDataArr); + } + contentJson.put(aiFormSettingDetail.getFormProp(), relateTableDataArr); + System.out.println(tableData); + } + } + } + } + } + + } + + + private String getFormattedFormSettingDetails(List aiFormSettingDetailList) { + StringBuilder sb = new StringBuilder("字段列表:\n"); + for (AiFormSettingDetail aiFormSettingDetail : aiFormSettingDetailList) { + if (aiFormSettingDetail.getSettingFlag().equals("1")) { + sb.append("- 字段名:").append(aiFormSettingDetail.getFieldName()) + .append(",返回的JSON数据Key值:").append(aiFormSettingDetail.getFormProp()) + .append(",字段描述:").append(aiFormSettingDetail.getFieldDesc()); + String fieldType = StringUtils.isBlank(aiFormSettingDetail.getFieldType()) ? HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_NORMAL : aiFormSettingDetail.getFieldType(); + if (fieldType.equals(HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_RELATE)) { + sb.append(" 备注:如果需要从关联表获取数据,则返回此关联表的查询条件即可,返回示例如下:[{'fieldName':'fieldValue'}],fieldName从字段名获取,如果不需要从关联表获取数据则返回空"); + } else if (fieldType.equals(HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_DICT)) { + sb.append(" 备注:如果有符合条件的数据,则根据要求返回字典的数值"); + } + sb.append("\n"); + } + + } + return sb.toString(); + } + + + /** + * 增强版的驼峰转下划线,处理各种边界情况 + */ + public String camelToSnakeEnhanced(String camelCase) { + if (camelCase == null || camelCase.isEmpty()) { + return camelCase; + } + + // 处理全大写的情况(如"URL" -> "url") + if (camelCase.equals(camelCase.toUpperCase())) { + return camelCase.toLowerCase(); + } + + String result = camelCase.replaceAll("([a-z])([A-Z])", "$1_$2") + .replaceAll("([A-Z])([A-Z][a-z])", "$1_$2") + .toLowerCase(); + + return result; + } + + + // /** // * 在新建AI模型或修改AI模型时,测试AI模型是否可用,验证apikey和apisecret等信息 // * @param provider // * @param aiRequest @@ -394,17 +583,4 @@ public class AIAssistantServiceImpl implements IAIAssistantService { // // return true; // } - - - public String aiFillForm() { - String aiClient = "deepSeek"; - IUnifiedAIProviderProcessor service = aiProviderProcessorMap.get(aiClient); - if (service == null) { - throw new IllegalArgumentException("Unsupported payment type"); - } - - return ""; - } - - } diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AiFormSettingServiceImpl.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AiFormSettingServiceImpl.java index fbff103e..36f4b504 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AiFormSettingServiceImpl.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AiFormSettingServiceImpl.java @@ -10,6 +10,7 @@ import org.anyline.metadata.Table; import org.anyline.proxy.ServiceProxy; import org.dromara.ai.domain.AiChatMessage; import org.dromara.ai.domain.AiFormSettingDetail; +import org.dromara.ai.domain.bo.AiFormSettingDetailBo; import org.dromara.ai.domain.vo.AiFormSettingDetailVo; import org.dromara.ai.mapper.AiFormSettingDetailMapper; import org.dromara.common.core.utils.MapstructUtils; @@ -53,19 +54,23 @@ public class AiFormSettingServiceImpl implements IAiFormSettingService { * @return AI表单设置 */ @Override - public AiFormSettingVo queryById(Long formSettingId){ + public AiFormSettingVo queryById(Long formSettingId) { MPJLambdaWrapper lqw = JoinWrappers.lambda(AiFormSettingDetail.class) .select(AiFormSettingDetail::getSettingDetailId) .select(AiFormSettingDetail::getFieldName) .select(AiFormSettingDetail::getFieldDesc) .select(AiFormSettingDetail::getFormProp) .select(AiFormSettingDetail::getSettingFlag) + .select(AiFormSettingDetail::getFieldStyle) + .select(AiFormSettingDetail::getFieldType) + .select(AiFormSettingDetail::getRelateTableFields) + .select(AiFormSettingDetail::getRelateFilterCondition) .eq(AiFormSettingDetail::getFormSettingId, formSettingId); List aiFormSettingDetailList = aiFormSettingDetailMapper.selectList(lqw); AiFormSettingVo aiFormSetting = baseMapper.selectVoById(formSettingId); aiFormSetting.setAiFormSettingDetailList(aiFormSettingDetailList); - return aiFormSetting; + return aiFormSetting; } /** @@ -97,17 +102,17 @@ public class AiFormSettingServiceImpl implements IAiFormSettingService { private MPJLambdaWrapper buildQueryWrapper(AiFormSettingBo bo) { Map params = bo.getParams(); MPJLambdaWrapper lqw = JoinWrappers.lambda(AiFormSetting.class) - .selectAll(AiFormSetting.class) - .eq(bo.getFormSettingId() != null, AiFormSetting::getFormSettingId, bo.getFormSettingId()) - .eq(StringUtils.isNotBlank(bo.getFormType()), AiFormSetting::getFormType, bo.getFormType()) - .like(StringUtils.isNotBlank(bo.getTableName()), AiFormSetting::getTableName, bo.getTableName()) - .like(StringUtils.isNotBlank(bo.getFormName()), AiFormSetting::getFormName, bo.getFormName()) - .like(StringUtils.isNotBlank(bo.getFormPath()), AiFormSetting::getFormPath, bo.getFormPath()) - .eq(StringUtils.isNotBlank(bo.getDialogVisibleVariable()), AiFormSetting::getDialogVisibleVariable, bo.getDialogVisibleVariable()) - .like(StringUtils.isNotBlank(bo.getSubTableName()), AiFormSetting::getSubTableName, bo.getSubTableName()) - .like(StringUtils.isNotBlank(bo.getSubTableFkName()), AiFormSetting::getSubTableFkName, bo.getSubTableFkName()) - .eq(StringUtils.isNotBlank(bo.getClientType()), AiFormSetting::getClientType, bo.getClientType()) - .orderByDesc(AiFormSetting::getCreateTime); + .selectAll(AiFormSetting.class) + .eq(bo.getFormSettingId() != null, AiFormSetting::getFormSettingId, bo.getFormSettingId()) + .eq(StringUtils.isNotBlank(bo.getFormType()), AiFormSetting::getFormType, bo.getFormType()) + .like(StringUtils.isNotBlank(bo.getTableName()), AiFormSetting::getTableName, bo.getTableName()) + .like(StringUtils.isNotBlank(bo.getFormName()), AiFormSetting::getFormName, bo.getFormName()) + .like(StringUtils.isNotBlank(bo.getFormPath()), AiFormSetting::getFormPath, bo.getFormPath()) + .eq(StringUtils.isNotBlank(bo.getDialogVisibleVariable()), AiFormSetting::getDialogVisibleVariable, bo.getDialogVisibleVariable()) + .like(StringUtils.isNotBlank(bo.getSubTableName()), AiFormSetting::getSubTableName, bo.getSubTableName()) + .like(StringUtils.isNotBlank(bo.getSubTableFkName()), AiFormSetting::getSubTableFkName, bo.getSubTableFkName()) + .eq(StringUtils.isNotBlank(bo.getClientType()), AiFormSetting::getClientType, bo.getClientType()) + .orderByDesc(AiFormSetting::getCreateTime); return lqw; } @@ -151,7 +156,7 @@ public class AiFormSettingServiceImpl implements IAiFormSettingService { /** * 保存前的数据校验 */ - private void validEntityBeforeSave(AiFormSetting entity){ + private void validEntityBeforeSave(AiFormSetting entity) { //TODO 做一些数据校验,如唯一约束 } @@ -165,7 +170,7 @@ public class AiFormSettingServiceImpl implements IAiFormSettingService { @Override @Transactional(rollbackFor = Exception.class) public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if(isValid){ + if (isValid) { //TODO 做一些业务上的校验,判断是否需要校验 } ids.forEach(id -> { @@ -177,16 +182,11 @@ public class AiFormSettingServiceImpl implements IAiFormSettingService { } - - - - - /** * 查询数据库列表 * * @param aiFormSettingBo AiFormSettingBo - * @param pageQuery 包含分页信息的PageQuery对象 + * @param pageQuery 包含分页信息的PageQuery对象 * @return 包含分页结果的TableDataInfo对象 */ @DS("#aiFormSettingBo.dataName") @@ -281,9 +281,32 @@ public class AiFormSettingServiceImpl implements IAiFormSettingService { return aiFormSettingDetailList; } + /** + * 获取AI表单设置属性列表 + * + * @param aiFormSettingDetailBo + * @return + */ + @Override + public List selectFormSettingDetailList(AiFormSettingDetailBo aiFormSettingDetailBo) { + MPJLambdaWrapper lqw = JoinWrappers.lambda(AiFormSettingDetail.class) + .select(AiFormSettingDetail::getSettingDetailId) + .select(AiFormSettingDetail::getFieldName) + .select(AiFormSettingDetail::getFieldDesc) + .select(AiFormSettingDetail::getFormProp) + .select(AiFormSettingDetail::getSettingFlag) + .select(AiFormSettingDetail::getFieldType) + .select(AiFormSettingDetail::getRelateTableFields) + .select(AiFormSettingDetail::getRelateTableName) + .select(AiFormSettingDetail::getRelateTableDesc) + .select(AiFormSettingDetail::getRelateFilterCondition) + .eq(AiFormSettingDetail::getFormSettingId, aiFormSettingDetailBo.getFormSettingId()) + .eq(AiFormSettingDetail::getSettingFlag, aiFormSettingDetailBo.getSettingFlag()); + List aiFormSettingDetailList = aiFormSettingDetailMapper.selectVoList(lqw); + return aiFormSettingDetailList; + } /** - * * @param snakeCaseStr * @return */ diff --git a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AiSqlTableServiceImpl.java b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AiSqlTableServiceImpl.java index 90626c0c..88b9bfdc 100644 --- a/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AiSqlTableServiceImpl.java +++ b/ruoyi-modules/hwmom-ai/src/main/java/org/dromara/ai/service/impl/AiSqlTableServiceImpl.java @@ -27,44 +27,11 @@ import org.dromara.ai.service.IAiSqlTableService; import java.util.*; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.lang.Dict; -import cn.hutool.core.util.ObjectUtil; -import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.dynamic.datasource.annotation.DSTransactional; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.anyline.metadata.Column; import org.anyline.metadata.Table; import org.anyline.proxy.ServiceProxy; -import org.dromara.common.core.constant.Constants; -import org.dromara.common.core.exception.ServiceException; -import org.dromara.common.core.utils.SpringUtils; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.core.utils.file.FileUtils; -import org.dromara.common.json.utils.JsonUtils; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.satoken.utils.LoginHelper; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; + /** * AI生成sql信息Service业务层处理 diff --git a/ruoyi-modules/hwmom-ai/src/main/resources/application.yml b/ruoyi-modules/hwmom-ai/src/main/resources/application.yml index 48f6b320..c10f9c4e 100644 --- a/ruoyi-modules/hwmom-ai/src/main/resources/application.yml +++ b/ruoyi-modules/hwmom-ai/src/main/resources/application.yml @@ -31,4 +31,5 @@ spring: import: - optional:nacos:application-common.yml - optional:nacos:datasource.yml + - optional:nacos:ruoyi-resource.yml - optional:nacos:${spring.application.name}.yml diff --git a/ruoyi-modules/hwmom-ai/src/main/resources/mapper/ai/AiFormSettingDetailMapper.xml b/ruoyi-modules/hwmom-ai/src/main/resources/mapper/ai/AiFormSettingDetailMapper.xml index ff325515..9900314e 100644 --- a/ruoyi-modules/hwmom-ai/src/main/resources/mapper/ai/AiFormSettingDetailMapper.xml +++ b/ruoyi-modules/hwmom-ai/src/main/resources/mapper/ai/AiFormSettingDetailMapper.xml @@ -5,10 +5,10 @@ - insert into ai_form_setting_detail (form_setting_id, table_name, field_name, field_desc, form_prop,setting_flag) + insert into ai_form_setting_detail (form_setting_id, table_name, field_name, field_desc, form_prop,setting_flag,field_type,field_style,sql_sample) values - (#{item.formSettingId}, #{item.tableName}, #{item.fieldName}, #{item.fieldDesc}, #{item.formProp},#{item.settingFlag}) + (#{item.formSettingId}, #{item.tableName}, #{item.fieldName}, #{item.fieldDesc}, #{item.formProp},#{item.settingFlag},#{item.fieldType},#{item.fieldStyle},#{item.sqlSample}) diff --git a/ruoyi-modules/hwmom-ai/src/main/resources/mapper/ai/SQLServerDatabaseMetaMapper.xml b/ruoyi-modules/hwmom-ai/src/main/resources/mapper/ai/SQLServerDatabaseMetaMapper.xml index 7f95f9b6..d6d2e51b 100644 --- a/ruoyi-modules/hwmom-ai/src/main/resources/mapper/ai/SQLServerDatabaseMetaMapper.xml +++ b/ruoyi-modules/hwmom-ai/src/main/resources/mapper/ai/SQLServerDatabaseMetaMapper.xml @@ -75,4 +75,74 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + +