From a8c6a6fbf95ecb3807a19da3613e8a5e7a91f0d5 Mon Sep 17 00:00:00 2001 From: dengzedong <dengzedong@email> Date: 星期五, 08 十一月 2024 09:31:23 +0800 Subject: [PATCH] 模型运行参数缓存 --- iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/utils/DllUtils.java | 3 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/MdkConstant.java | 8 ++ iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java | 88 +++++++++++++++++++--- iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java | 5 + iailab-module-model/iailab-module-model-biz/src/main/resources/template/impl.java.vm | 3 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MdkDTO.java | 4 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MdkController.java | 84 ++++++++++++++++---- 7 files changed, 163 insertions(+), 32 deletions(-) diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/MdkConstant.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/MdkConstant.java index ab8c089..fcc9adf 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/MdkConstant.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/MdkConstant.java @@ -46,4 +46,12 @@ * 项目发布dll和jar目录 */ String PROJECT_PUBLISH = "projectPublish"; + /** + * setup.py + */ + String SETUP_PY = "setup.py"; + /** + * 编译pyd生成文件后缀 + */ + String PYD_SUFFIX = ".cp37-win_amd64.pyd"; } \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/utils/DllUtils.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/utils/DllUtils.java index 947da19..ae18b35 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/utils/DllUtils.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/common/utils/DllUtils.java @@ -217,6 +217,9 @@ throw new RuntimeException("模型文件不能为空!"); } else { URLClassLoader classLoader = DllUtils.getClassLoader(projectId); + if (null == classLoader) { + throw new RuntimeException("dll未发布,classLoader为null"); + } Class<?> clazz = classLoader.loadClass(model.getClassName()); Method method = clazz.getMethod(model.getMethodName(), model.getParamsArray()); return (HashMap)method.invoke(clazz.newInstance(), paramsValueArray); diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MdkController.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MdkController.java index 8d75179..bd527a4 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MdkController.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MdkController.java @@ -1,5 +1,7 @@ package com.iailab.module.model.mpk.controller.admin; +import cn.hutool.cache.CacheUtil; +import cn.hutool.cache.impl.FIFOCache; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.iail.utils.RSAUtils; @@ -11,6 +13,7 @@ import com.iailab.module.model.mpk.common.utils.Readtxt; import com.iailab.module.model.mpk.dto.MdkDTO; import com.iailab.module.model.mpk.dto.MdkRunDTO; +import com.iailab.module.model.mpk.dto.MethodSettingDTO; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -24,6 +27,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.UUID; import static com.iailab.framework.common.pojo.CommonResult.error; import static com.iailab.framework.common.pojo.CommonResult.success; @@ -40,6 +44,8 @@ @Value("${mpk.bak-file-path}") private String mpkBakFilePath; + // 先进先出缓存 + private static FIFOCache<String, String> cache = CacheUtil.newFIFOCache(100); /** * @description: 模型测试运行 @@ -76,16 +82,19 @@ System.out.println("runTime=" + System.currentTimeMillis()); try { - List<String> datas = dto.getDatas(); + List<String> uuids = dto.getUuids(); - int paramLength = dto.getHasModel() ? datas.size() + 2 : datas.size() + 1; + int paramLength = dto.getHasModel() ? uuids.size() + 2 : uuids.size() + 1; Object[] paramsValueArray = new Object[paramLength]; Class<?>[] paramsArray = new Class[paramLength]; try { - for (int i = 0; i < datas.size(); i++) { - String json = datas.get(i); - JSONArray jsonArray = JSON.parseArray(json); + for (int i = 0; i < uuids.size(); i++) { + String uuid = uuids.get(i); + if (!cache.containsKey(uuid)) { + return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"请重新导入模型参数"); + } + JSONArray jsonArray = JSON.parseArray(cache.get(uuid)); double[][] data = new double[jsonArray.size()][jsonArray.getJSONArray(0).size()]; for (int j = 0; j < jsonArray.size(); j++) { for (int k = 0; k < jsonArray.getJSONArray(j).size(); k++) { @@ -97,17 +106,22 @@ } } catch (Exception e) { e.printStackTrace(); - return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"参数错误,请检查!"); + return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"模型参数错误,请检查!"); } - if (dto.getHasModel()) { - paramsValueArray[datas.size()] = dto.getModel(); - paramsValueArray[datas.size() + 1] = dto.getModelSettings(); - paramsArray[datas.size()] = HashMap.class; - paramsArray[datas.size() + 1] = HashMap.class; - }else { - paramsValueArray[datas.size()] = dto.getModelSettings(); - paramsArray[datas.size()] = HashMap.class; + try { + if (dto.getHasModel()) { + paramsValueArray[uuids.size()] = dto.getModel(); + paramsValueArray[uuids.size() + 1] = handleModelSettings(dto.getModelSettings()); + paramsArray[uuids.size()] = HashMap.class; + paramsArray[uuids.size() + 1] = HashMap.class; + }else { + paramsValueArray[uuids.size()] = handleModelSettings(dto.getModelSettings()); + paramsArray[uuids.size()] = HashMap.class; + } + } catch (Exception e) { + e.printStackTrace(); + return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"模型设置错误,请检查!"); } HashMap result = (HashMap) clazz.getDeclaredMethod(dto.getMethodName(), paramsArray).invoke(clazz.newInstance(), paramsValueArray); @@ -122,6 +136,37 @@ } System.gc(); } + } + + private HashMap<String, Object> handleModelSettings(List<MethodSettingDTO> modelSettings) { + HashMap<String, Object> resultMap = null; + try { + resultMap = new HashMap<>(modelSettings.size()); + for (MethodSettingDTO modelSetting : modelSettings) { + switch (modelSetting.getValueType()) { + case "int": + resultMap.put(modelSetting.getSettingKey(), Integer.valueOf(modelSetting.getSettingValue())); + break; + case "string": + resultMap.put(modelSetting.getSettingKey(), modelSetting.getSettingValue()); + break; + case "decimal": + resultMap.put(modelSetting.getSettingKey(), Double.valueOf(modelSetting.getSettingValue())); + break; + case "decimalArray": + JSONArray jsonArray = JSON.parseArray(modelSetting.getSettingValue()); + double[] doubles = new double[jsonArray.size()]; + for (int i = 0; i < jsonArray.size(); i++) { + doubles[i] = Double.valueOf(String.valueOf(jsonArray.get(i))); + } + resultMap.put(modelSetting.getSettingKey(), doubles); + break; + } + } + } catch (NumberFormatException e) { + throw new RuntimeException("模型参数有误,请检查!!!"); + } + return resultMap; } /** @@ -157,13 +202,18 @@ @PostMapping("/import") @Operation(summary = "导入参数") - public CommonResult<List<String>> importExcel(@RequestParam("file") MultipartFile file) throws Exception { + public CommonResult<List<HashMap<String,Object>>> importExcel(@RequestParam("file") MultipartFile file) throws Exception { List<double[][]> datas = Readtxt.readMethodExcel(file); - List<String> result = new ArrayList<>(); + List<HashMap<String,Object>> result = new ArrayList<>(); if (!CollectionUtils.isEmpty(datas)) { for (double[][] data : datas) { if (data.length > 0) { - result.add(JSON.toJSONString(data)); + HashMap<String,Object> map = new HashMap<>(); + String uuid = UUID.randomUUID().toString(); + map.put("uuid",uuid); + map.put("data",JSON.toJSONString(data)); + cache.put(uuid,JSON.toJSONString(data)); + result.add(map); } } } diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MdkDTO.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MdkDTO.java index ad08abe..8727d80 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MdkDTO.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MdkDTO.java @@ -25,7 +25,7 @@ private HashMap<String, Object> model; - private HashMap<String, Object> modelSettings; + private List<MethodSettingDTO> modelSettings; - private List<String> datas; + private List<String> uuids; } \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java index fce3f21..4b322e3 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java @@ -61,4 +61,9 @@ private Integer min; private List<SettingSelectDTO> settingSelects; + + /** + * 参数值 + */ + private String settingValue; } \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java index afe68d0..3db6b2b 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java @@ -22,7 +22,6 @@ import com.iailab.module.model.mpk.dto.GeneratorCodeHistoryDTO; import com.iailab.module.model.mpk.dto.ModelMethodDTO; import com.iailab.module.model.mpk.dto.MpkFileDTO; -import com.iailab.module.model.mpk.dto.ProjectPackageHistoryDTO; import com.iailab.module.model.mpk.entity.GeneratorCodeHistoryEntity; import com.iailab.module.model.mpk.entity.MpkFileEntity; import com.iailab.module.model.mpk.entity.ProjectPackageHistoryEntity; @@ -246,6 +245,11 @@ //生成Jni.h文件 File jniHFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.h"); GenUtils.drawTemplate("Jni.h.vm", dataContext, jniHFile); + + // 添加python源文件 + String pyFilePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.ALGS + File.separator + entity.getPyModule().replace(".", File.separator) + File.separator + entity.getPyName() + ".pyd"; + FileUtil.mkParentDirs(pyFilePath); + FileUtil.copy(entity.getFilePath(), pyFilePath, true); // 资源文件 FileUtil.copy(mpkResources + File.separator + "libs", dirPath.getAbsolutePath(), true); @@ -492,26 +496,86 @@ Long tenantId = TenantContextHolder.getTenantId(); // 备份文件 租户隔离 String mpkTenantBakFilePath = mpkBakFilePath + File.separator + tenantId; - - File dir = new File(mpkTenantBakFilePath); - if (!dir.exists()) { - dir.mkdirs(); + File bakDir = new File(mpkTenantBakFilePath); + if (!bakDir.exists()) { + bakDir.mkdirs(); + } + //临时文件夹 + File tempDir = null; + try { + tempDir = Files.createTempDirectory("pyFileTmp").toFile(); + log.info("生成临时文件夹," + tempDir.getAbsolutePath()); + } catch (IOException e) { + throw new RuntimeException("创建临时文件夹异常",e); } String fileName = file.getOriginalFilename(); - String fileSuffix = fileName.substring(fileName.lastIndexOf(".")); - File saveFile = new File(dir.getAbsolutePath() + File.separator + UUID.randomUUID() + fileSuffix); + File pydBakFile = new File(bakDir.getAbsolutePath() + File.separator + UUID.randomUUID() + ".pyd"); - saveFile.createNewFile(); - // 保存 - file.transferTo(saveFile); + String pyName = fileName.substring(0, fileName.lastIndexOf(".")); + try { + // py文件存入临时文件夹 + File saveFile = new File(tempDir.getAbsolutePath() + File.separator + fileName); + saveFile.createNewFile(); + file.transferTo(saveFile); + + // 临时文件夹中生成pyd文件 + // 生成setup.py文件 + createSetUpFile(tempDir.getAbsolutePath(),fileName,pyName); + // 执行cmd命令编译pyd文件 + createPydFile(tempDir.getAbsolutePath()); + + // 临时文件夹中pyd文件移到dir下,修改为uuid.pyd + File pydFile = new File(tempDir.getAbsolutePath() + File.separator + pyName + MdkConstant.PYD_SUFFIX); + if (!pydFile.exists()) { + throw new RuntimeException("编译pyd文件失败!"); + } + log.info("备份pyd文件," + pydBakFile.getAbsolutePath()); + FileUtil.copy(pydFile,pydBakFile,true); + } catch (Exception e) { + throw new RuntimeException("编译pyd文件异常"); + } finally { + if (tempDir.exists()) { + tempDir.delete(); + } + } Map<String, String> result = new HashMap<>(2); - result.put("filePath", saveFile.getAbsolutePath()); - result.put("fileName", fileName); + result.put("filePath", pydBakFile.getAbsolutePath()); + result.put("fileName", pyName); return result; } + private void createPydFile(String dir) { + try { + String command = "python setup.py build_ext --inplace"; + log.info("执行cmd命令编译pyd:" + command); + ProcessBuilder builder = new ProcessBuilder("cmd", "/c", command); + builder.directory(new File(dir)); // 设置工作目录 + builder.redirectErrorStream(true); // 将错误输出和标准输出合并 + Process process = builder.start(); + // 获取命令输出结果 + InputStream inputStream = process.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "GBK")); // 设置编码为GBK + String line; + while ((line = reader.readLine()) != null) { + log.info(line); + } + // 等待命令执行完成 + process.waitFor(); + } catch (Exception e) { + throw new RuntimeException("执行cmd命令生成dll异常", e); + } + } + + private void createSetUpFile(String dir, String pyFileName, String pyName) { + // 生成setup.py文件 + HashMap<String,Object> map = new HashMap<>(); + map.put("fileName",pyFileName); + map.put("pyName",pyName); + GenUtils.drawTemplate("setup.py.vm",map,new File(dir + File.separator + MdkConstant.SETUP_PY)); + } + @Override public CommonResult<String> publish(Map<String, Object> params) { String historyId = (String) params.get("historyId"); diff --git a/iailab-module-model/iailab-module-model-biz/src/main/resources/template/impl.java.vm b/iailab-module-model/iailab-module-model-biz/src/main/resources/template/impl.java.vm index 0ffc252..f1ebee1 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/resources/template/impl.java.vm +++ b/iailab-module-model/iailab-module-model-biz/src/main/resources/template/impl.java.vm @@ -18,7 +18,8 @@ @Override public HashMap<String, Object> ${entity.methodName}(#foreach ($column in [1..$entity.dataLength])double data${column}[][], #{end}#{if}($entity.model==1)HashMap<String, Object> models, #{end}HashMap<String, Object> settings) { #{if}($entity.model==1) - model = utils.createPredictHashmapplus(models); + //model = utils.createPredictHashmapplus(models); + model = models; #{end} if (#{foreach} ($column in [1..$entity.dataLength])#{if}($column==1)data${column} == null || data${column}.length == 0 || data${column}[0].length == 0#{else} || data${column} == null || data${column}.length == 0 || data${column}[0].length == 0#{end}#{end}) { result = new HashMap<String, Object>(); -- Gitblit v1.9.3