package com.iailab.module.model.mpk.controller.admin; import cn.hutool.cache.CacheUtil; import cn.hutool.cache.impl.FIFOCache; import cn.hutool.core.io.FileUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.iail.IAILMDK; import com.iail.bean.FieldSet; import com.iail.bean.Property; import com.iail.bean.SelectItem; import com.iail.model.IAILModel; import com.iail.utils.RSAUtils; import com.iailab.framework.common.exception.enums.GlobalErrorCodeConstants; import com.iailab.framework.common.pojo.CommonResult; import com.iailab.framework.tenant.core.context.TenantContextHolder; import com.iailab.module.model.mpk.common.MdkConstant; import com.iailab.module.model.mpk.common.utils.DllUtils; 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.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.net.URLClassLoader; import java.net.URLEncoder; import java.nio.file.Files; import java.util.*; import java.util.stream.Collectors; import static com.iailab.framework.common.pojo.CommonResult.error; import static com.iailab.framework.common.pojo.CommonResult.success; /** * @author PanZhibao * @Description * @createTime 2024年08月08日 */ @RestController @Slf4j @RequestMapping("/model/mpk/api") public class MdkController { @Value("${mpk.bak-file-path}") private String mpkBakFilePath; // 先进先出缓存 临时保存导入的数据 private static FIFOCache cache = CacheUtil.newFIFOCache(100); /** * @description: 模型测试运行 * @author: dzd * @date: 2024/10/14 15:26 **/ @PostMapping("test") public CommonResult test(@RequestBody MdkDTO dto) { Long tenantId = TenantContextHolder.getTenantId(); // 备份文件 租户隔离 String mpkTenantBakFilePath = mpkBakFilePath + File.separator + tenantId; Class clazz; URLClassLoader classLoader; try { File jarFile = new File(mpkTenantBakFilePath + File.separator + MdkConstant.JAR + File.separator + dto.getPyName() + ".jar"); if (!jarFile.exists()) { throw new RuntimeException("jar包不存在,请先生成代码。jarPath:" + jarFile.getAbsolutePath()); } File dllFile = new File(mpkTenantBakFilePath + File.separator + MdkConstant.DLL + File.separator + dto.getPyName() + ".dll"); if (!dllFile.exists()) { throw new RuntimeException("dll文件不存在,请先生成代码。dllPath:" + dllFile.getAbsolutePath()); } // 加载jar包 classLoader = DllUtils.loadJar(jarFile.getAbsolutePath()); // 实现类 clazz = classLoader.loadClass(dto.getClassName()); // 加载dll到实现类 DllUtils.loadDll(clazz,dllFile.getAbsolutePath()); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("加载运行环境失败。"); } System.out.println("runTime=" + System.currentTimeMillis()); try { List uuids = dto.getUuids(); 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 < 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++) { data[j][k] = jsonArray.getJSONArray(j).getDoubleValue(k); } } paramsValueArray[i] = data; paramsArray[i] = double[][].class; } } catch (Exception e) { e.printStackTrace(); return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"模型参数错误,请检查!"); } try { if (dto.getModelSettings().stream().noneMatch(e -> e.getSettingKey().equals(MdkConstant.PY_FILE_KEY))) { return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"模型设置参数缺少必要信息【" + MdkConstant.PY_FILE_KEY + "】,请重新上传模型!"); } 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); return success(JSON.toJSONString(result)); } catch (Exception ex) { ex.printStackTrace(); return error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"运行异常"); } finally { if (classLoader != null) { DllUtils.unloadDll(classLoader); DllUtils.unloadJar(classLoader); } System.gc(); } } private IAILModel createModelBean(MdkDTO dto) { IAILModel modelBean = new IAILModel(); //ParamPathList List paramPathList = new ArrayList<>(); List paramNameList = new ArrayList<>(); for (Map.Entry entry : dto.getModel().entrySet()) { paramNameList.add(entry.getKey()); paramPathList.add(entry.getValue().toString()); } modelBean.setParamNameList(paramNameList); modelBean.setParamPathList(paramPathList); //ClassName MethodName modelBean.setClassName(dto.getClassName()); modelBean.setMethodName(dto.getMethodName()); //ParamsArray int paramLength = dto.getHasModel() ? dto.getDataLength() + 2 : dto.getDataLength() + 1; Class[] paramsArray = new Class[paramLength]; for (int i = 0; i < dto.getDataLength(); i++) { paramsArray[i] = double[][].class; } if (dto.getHasModel()) { paramsArray[dto.getDataLength()] = HashMap.class; paramsArray[dto.getDataLength() + 1] = HashMap.class; }else { paramsArray[dto.getDataLength()] = HashMap.class; } modelBean.setParamsArray(paramsArray); //LoadFieldSetList List
loadFieldSetList = new ArrayList<>(); FieldSet fieldSet = new FieldSet(); fieldSet.setFieldName(""); List propertyList = new ArrayList<>(); for (MethodSettingDTO modelSetting : dto.getPredModelSettings()) { Property property = new Property(); property.setKey(modelSetting.getSettingKey()); property.setName(modelSetting.getName()); property.setType(modelSetting.getType()); property.setValueType(modelSetting.getValueType()); property.setMin(modelSetting.getMin() == null ? "" : modelSetting.getMin().toString()); property.setMax(modelSetting.getMax() == null ? "" : modelSetting.getMax().toString()); property.setSelectItemList(CollectionUtils.isEmpty(modelSetting.getSettingSelects()) ? null : modelSetting.getSettingSelects().stream().map(e -> new SelectItem(e.getSelectKey(),e.getName())).collect(Collectors.toList())); property.setValue(modelSetting.getValue()); property.setFlow(false); propertyList.add(property); } fieldSet.setPropertyList(propertyList); loadFieldSetList.add(fieldSet); modelBean.setLoadFieldSetList(loadFieldSetList); //SettingConfigMap Map settingConfigMap = new HashMap(); List settingKeyList = new ArrayList(); Map settingMap = new HashMap(); for (MethodSettingDTO modelSetting : dto.getModelSettings()) { settingKeyList.add(new com.iail.bean.Value(modelSetting.getSettingKey(),modelSetting.getSettingKey())); settingConfigMap.put("settingKeyList", settingKeyList); settingConfigMap.put("settingMap", handleModelSettings(dto.getModelSettings())); } modelBean.setSettingConfigMap(settingConfigMap); //DataMap modelBean.setDataMap(dto.getModelResult()); //ResultKey modelBean.setResultKey(dto.getResultKey()); //ResultKey modelBean.setVersion("1.0.0"); return modelBean; } @PostMapping("saveModel") public void saveModel(@RequestBody MdkDTO dto, HttpServletResponse response) { IAILModel modelBean = createModelBean(dto); try { //临时文件夹 File tempFile = null; try { tempFile = Files.createTempFile(dto.getPyName(),".miail").toFile(); log.info("生成临时文件," + tempFile.getAbsolutePath()); } catch (IOException e) { throw new RuntimeException("创建临时文件异常",e); } try { IAILMDK.saveModel(tempFile, modelBean); } catch (Exception e) { throw new RuntimeException("IAILMDK.saveModel异常",e); } byte[] data = FileUtil.readBytes(tempFile); response.reset(); response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(tempFile.getName(), "UTF-8") + "\""); response.addHeader("Content-Length", "" + data.length); response.setContentType("application/octet-stream; charset=UTF-8"); IOUtils.write(data, response.getOutputStream()); } catch (Exception e) { throw new RuntimeException("代码生成异常",e); } } private HashMap handleModelSettings(List modelSettings) { HashMap 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; } /** * @description: 模型运行 * @author: dzd * @date: 2024/10/14 15:26 **/ @PostMapping("run") public CommonResult run(@RequestBody MdkRunDTO dto) { if (RSAUtils.checkLisenceBean().getCode() != 1) { log.error("Lisence 不可用!"); return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"Lisence 不可用!"); } else { try { URLClassLoader classLoader = DllUtils.getClassLoader(dto.getProjectId()); if (null == classLoader) { return CommonResult.error(GlobalErrorCodeConstants.ERROR_CONFIGURATION.getCode(),"请先发布项目!"); } Class clazz = classLoader.loadClass(dto.getClassName()); Method method = clazz.getMethod(dto.getMethodName(), dto.getParamsClassArray()); HashMap invoke = (HashMap) method.invoke(clazz.newInstance(), dto.getParamsValueArray()); // todo 将结果存入数据库 } catch (Exception e) { log.error("模型运行失败",e); return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"模型运行失败!"); } } return CommonResult.success(""); } @PostMapping("/import") @Operation(summary = "导入参数") public CommonResult>> importExcel(@RequestParam("file") MultipartFile file) throws Exception { List datas = Readtxt.readMethodExcel(file); List> result = new ArrayList<>(); if (!CollectionUtils.isEmpty(datas)) { for (double[][] data : datas) { if (data.length > 0) { HashMap 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); } } } return success(result); } }