dengzedong
2025-02-27 3e61b6d86d6a98214e56c652a36a2290d471a695
提交 | 用户 | 时间
3e61b6 1 package com.iailab.module.model.matlab.service.impl;
D 2
3
4 import cn.hutool.cache.CacheUtil;
5 import cn.hutool.cache.impl.FIFOCache;
6 import cn.hutool.core.io.FileUtil;
7 import com.alibaba.fastjson.JSON;
8 import com.alibaba.fastjson.JSONArray;
9 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
10 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
11 import com.baomidou.mybatisplus.core.metadata.IPage;
12 import com.iailab.framework.common.exception.enums.GlobalErrorCodeConstants;
13 import com.iailab.framework.common.page.PageData;
14 import com.iailab.framework.common.pojo.CommonResult;
15 import com.iailab.framework.common.service.impl.BaseServiceImpl;
16 import com.iailab.framework.common.util.object.ConvertUtils;
17 import com.iailab.framework.security.core.util.SecurityFrameworkUtils;
18 import com.iailab.framework.tenant.core.context.TenantContextHolder;
19 import com.iailab.module.model.common.utils.DateUtils;
20 import com.iailab.module.model.matlab.common.exceptions.IllegalityJarException;
21 import com.iailab.module.model.matlab.common.utils.MatlabUtils;
22 import com.iailab.module.model.matlab.dao.MlModelDao;
23 import com.iailab.module.model.matlab.dto.MatlabJarFileInfoDTO;
24 import com.iailab.module.model.matlab.dto.MatlabRunDTO;
25 import com.iailab.module.model.matlab.dto.MlModelDTO;
26 import com.iailab.module.model.matlab.entity.MlModelEntity;
27 import com.iailab.module.model.matlab.service.MlModelMethodService;
28 import com.iailab.module.model.matlab.service.MlModelService;
29 import com.iailab.module.model.mpk.common.MdkConstant;
30 import com.iailab.module.model.mpk.common.utils.Readtxt;
31 import com.mathworks.toolbox.javabuilder.MWStructArray;
32 import lombok.extern.slf4j.Slf4j;
33 import org.apache.commons.lang3.StringUtils;
34 import org.springframework.beans.factory.annotation.Autowired;
35 import org.springframework.beans.factory.annotation.Value;
36 import org.springframework.stereotype.Service;
37 import org.springframework.util.CollectionUtils;
38 import org.springframework.web.multipart.MultipartFile;
39
40 import java.io.File;
41 import java.io.IOException;
42 import java.net.URLClassLoader;
43 import java.util.*;
44
45 import static com.iailab.framework.common.pojo.CommonResult.error;
46 import static com.iailab.framework.common.pojo.CommonResult.success;
47
48 /**
49  * 
50  *
51  * @author Dzd 
52  * @since 1.0.0 2025-02-08
53  */
54 @Slf4j
55 @Service
56 public class MlModelServiceImpl extends BaseServiceImpl<MlModelDao, MlModelEntity> implements MlModelService {
57
58     @Value("${mablab.bak-file-path}")
59     private String mablabBakFilePath;
60
61     @Autowired
62     private MlModelMethodService mlModelMethodService;
63
64     // 先进先出缓存 临时保存导入的数据
65     private static FIFOCache<String, String> cache = CacheUtil.newFIFOCache(100);
66
67     @Override
68     public PageData<MlModelDTO> page(Map<String, Object> params) {
69         IPage<MlModelEntity> page = baseDao.selectPage(
70                 getPage(params, "create_date", false),
71                 getWrapper(params)
72         );
73
74         return getPageData(page, MlModelDTO.class);
75     }
76
77     @Override
78     public List<MlModelDTO> list(Map<String, Object> params) {
79         List<MlModelDTO> list = baseDao.list(params);
80
81         return list;
82     }
83
84     private QueryWrapper<MlModelEntity> getWrapper(Map<String, Object> params) {
85         String modelName = (String) params.get("modelName");
86         String modelFileName = (String) params.get("modelFileName");
87
88         QueryWrapper<MlModelEntity> wrapper = new QueryWrapper<>();
89         wrapper.like(StringUtils.isNotBlank(modelName), "model_name", modelName)
90                 .like(StringUtils.isNotBlank(modelFileName), "model_file_name", modelFileName);
91         return wrapper;
92     }
93
94     @Override
95     public MlModelDTO get(String id) {
96         MlModelDTO entity = baseDao.get(id);
97
98         return entity;
99     }
100
101     @Override
102     @DSTransactional(rollbackFor = Exception.class)
103     public void save(MlModelDTO dto) {
104         MlModelEntity entity = ConvertUtils.sourceToTarget(dto, MlModelEntity.class);
105         entity.setId(UUID.randomUUID().toString());
106         entity.setModelFilePath(dto.getModelFilePath().trim());
107         entity.setModelFileName(dto.getModelFileName().trim());
108         entity.setCreator(SecurityFrameworkUtils.getLoginUserId());
109         entity.setCreateDate(new Date());
110         insert(entity);
111
112         mlModelMethodService.insertList(dto.getModelMethods(), entity.getId());
113
114         saveJarFile(dto.getModelFilePath(),dto.getModelFileName());
115     }
116
117     @Override
118     @DSTransactional(rollbackFor = Exception.class)
119     public void update(MlModelDTO dto) {
120         MlModelEntity entity = ConvertUtils.sourceToTarget(dto, MlModelEntity.class);
121         entity.setUpdater(SecurityFrameworkUtils.getLoginUserId());
122         entity.setUpdateDate(new Date());
123         updateById(entity);
124         mlModelMethodService.deleteModelMethod(entity.getId());
125         mlModelMethodService.insertList(dto.getModelMethods(), entity.getId());
126
127         saveJarFile(dto.getModelFilePath(),dto.getModelFileName());
128     }
129
130     /**
131      * @description: 保存最新jar文件,用于测试运行
132      * @author: dzd
133      * @date: 2025/2/24 16:25
134      **/
135     private void saveJarFile(String modelFilePath,String modelFileName) {
136         String matlabTenantBakFilePath = getMatlabTenantBakFilePath();
137
138         String jarBakPath = matlabTenantBakFilePath + File.separator + MdkConstant.JAR + File.separator + modelFileName + ".jar";
139         FileUtil.copy(modelFilePath, jarBakPath, true);
140     }
141
142     @Override
143     @DSTransactional(rollbackFor = Exception.class)
144     public void delete(String id) {
145
146         //删除源文件
147         MlModelEntity MlModelEntity = selectById(id);
148         if (StringUtils.isNoneBlank(MlModelEntity.getModelFilePath())) {
149             File mpkFile = new File(MlModelEntity.getModelFilePath());
150             if (mpkFile.exists()) {
151                 mpkFile.delete();
152                 log.info("删除源文件备份文件:" + MlModelEntity.getModelFilePath());
153             }
154         }
155         //删除 会级联删除掉关联表
156         deleteById(id);
157     }
158
159     @Override
160     public MatlabJarFileInfoDTO uploadJarFile(MultipartFile file) throws IllegalityJarException {
161         String matlabTenantBakFilePath = getMatlabTenantBakFilePath();
162         File bakDir = new File(matlabTenantBakFilePath);
163
164         String jarName = null;
165         File jarBakFile = null;
166         try {
167             String fileName = file.getOriginalFilename();
168             jarName = fileName.substring(0, fileName.lastIndexOf("."));
169             String pyName_time = jarName + "_" + DateUtils.format(new Date(),DateUtils.DATE_TIME_STRING);
170             jarBakFile = new File(bakDir.getAbsolutePath() + File.separator + pyName_time + ".jar");
171             file.transferTo(jarBakFile);
172         } catch (IOException e) {
173             throw new RuntimeException("保存算法封装jar文件失败!");
174         }
175
176         //解析jar info
177         MatlabJarFileInfoDTO result = new MatlabJarFileInfoDTO();
178         result.setFilePath(jarBakFile.getAbsolutePath());
179         result.setFileName(jarName);
180         result.setClassInfos(MatlabUtils.parseJarInfo(jarBakFile.getAbsolutePath(),jarName));
181         return result;
182     }
183
184     @Override
185     public CommonResult<String> test(MatlabRunDTO dto) {
186         String matlabTenantBakFilePath = getMatlabTenantBakFilePath();
187
188         Class<?> clazz;
189         URLClassLoader classLoader;
190         try {
191             File jarFile = new File(matlabTenantBakFilePath + File.separator + MdkConstant.JAR + File.separator + dto.getModelFileName() + ".jar");
192             if (!jarFile.exists()) {
193                 throw new RuntimeException("jar包不存在,请检查。jarPath:" + jarFile.getAbsolutePath());
194             }
195             // 加载jar包
196             classLoader = MatlabUtils.loadJar(null,jarFile.getAbsolutePath());
197             // 实现类
198             clazz = classLoader.loadClass(dto.getClassName());
199         } catch (Exception e) {
200             e.printStackTrace();
201             throw new RuntimeException("加载运行环境失败。");
202         }
203
204         try {
205             List<String> uuids = dto.getUuids();
206
207             Object[] paramsValueArray = new Object[uuids.size() + 1];
208
209             try {
210                 for (int i = 0; i < uuids.size(); i++) {
211                     String uuid = uuids.get(i);
212                     if (!cache.containsKey(uuid)) {
213                         return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"请重新导入模型参数");
214                     }
215                     JSONArray jsonArray = JSON.parseArray(cache.get(uuid));
216                     double[][] data = new double[jsonArray.size()][jsonArray.getJSONArray(0).size()];
217                     for (int j = 0; j < jsonArray.size(); j++) {
218                         for (int k = 0; k < jsonArray.getJSONArray(j).size(); k++) {
219                             data[j][k] = jsonArray.getJSONArray(j).getDoubleValue(k);
220                         }
221                     }
222                     paramsValueArray[i] = data;
223                 }
224             } catch (Exception e) {
225                 e.printStackTrace();
226                 return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"模型参数错误,请检查!");
227             }
228
229             MWStructArray mwStructArraySetting;
230             try {
231
232                 HashMap<String, Object> settings = MatlabUtils.handleModelSettings(dto.getModelSettings());
233                 mwStructArraySetting = MatlabUtils.convertMapToStruct(settings);
234                 paramsValueArray[uuids.size()] = mwStructArraySetting;
235             } catch (Exception e) {
236                 e.printStackTrace();
237                 return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"模型设置错误,请检查!");
238             }
239
240             Class<?>[] paramsArray = new Class[2];
241             paramsArray[0] = int.class;
242             paramsArray[1] = Object[].class;
243             Object[] objects = (Object[]) clazz.getDeclaredMethod(dto.getMethodName(), paramsArray).invoke(clazz.newInstance(), new Object[]{dto.getOutLength(), paramsValueArray});
244             mwStructArraySetting.dispose();
245             Map<String, Object> result = MatlabUtils.convertStructToMap((MWStructArray) objects[0]);
246             return success(JSON.toJSONString(result));
247         } catch (Exception ex) {
248             ex.printStackTrace();
249             return error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"运行异常");
250         } finally {
251             if (classLoader != null) {
252                 MatlabUtils.unloadJar(classLoader);
253             }
254         }
255     }
256
257     @Override
258     public List<HashMap<String, Object>> importData(MultipartFile file) throws IOException {
259         List<double[][]> datas = Readtxt.readMethodExcel(file);
260         List<HashMap<String,Object>> result = new ArrayList<>();
261         if (!CollectionUtils.isEmpty(datas)) {
262             for (double[][] data : datas) {
263                 if (data.length > 0) {
264                     HashMap<String,Object> map = new HashMap<>();
265                     String uuid = UUID.randomUUID().toString();
266                     map.put("uuid",uuid);
267                     map.put("data", JSON.toJSONString(data));
268                     cache.put(uuid,JSON.toJSONString(data));
269                     result.add(map);
270                 }
271             }
272         }
273         return result;
274     }
275
276     private String getMatlabTenantBakFilePath() {
277         Long tenantId = TenantContextHolder.getTenantId();
278         // 备份文件夹 租户隔离
279         String matlabTenantBakFilePath = mablabBakFilePath + File.separator + tenantId;
280         File bakDir = new File(matlabTenantBakFilePath);
281         if (!bakDir.exists()) {
282             bakDir.mkdirs();
283         }
284         return matlabTenantBakFilePath;
285     }
286
287 }