From 5a6d95d47cbef0f9568e83b9b3fe67fa3e18d7ec Mon Sep 17 00:00:00 2001 From: limin Date: Sat, 11 Jan 2025 16:04:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=9C=8D=E5=8A=A1=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E7=8A=B6=E6=80=81=E6=9F=A5=E8=AF=A2=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../llm/enums/ModelDeployConstantEnum.java | 60 +++++++++++++ .../modelservice/ModelServiceMapper.java | 5 +- .../AigcCustomDateTimeDeserializer.java | 31 +++++++ .../llm/service/http/TrainHttpService.java | 5 +- .../service/http/vo/AigcModelDeployVO.java | 63 +++++++++++++ .../ModelServiceTaskSyncService.java | 89 +++++++++++++++++++ 6 files changed, 250 insertions(+), 3 deletions(-) create mode 100644 yudao-module-llm/yudao-module-llm-api/src/main/java/cn/iocoder/yudao/module/llm/enums/ModelDeployConstantEnum.java create mode 100644 yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/handler/AigcCustomDateTimeDeserializer.java create mode 100644 yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcModelDeployVO.java create mode 100644 yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/modelservice/ModelServiceTaskSyncService.java diff --git a/yudao-module-llm/yudao-module-llm-api/src/main/java/cn/iocoder/yudao/module/llm/enums/ModelDeployConstantEnum.java b/yudao-module-llm/yudao-module-llm-api/src/main/java/cn/iocoder/yudao/module/llm/enums/ModelDeployConstantEnum.java new file mode 100644 index 000000000..9ee87e84a --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-api/src/main/java/cn/iocoder/yudao/module/llm/enums/ModelDeployConstantEnum.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.llm.enums; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum ModelDeployConstantEnum implements IntArrayValuable { + MODEL_DEPLOY_PENDING(1,"pending"), + MODEL_DEPLOY_RUNNING(2,"running"), + MODEL_DEPLOY_SUCCESS(2,"success"), + MODEL_DEPLOY_FAILED(3,"failed"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ModelDeployConstantEnum::getStatus).toArray(); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static boolean isEnable(Integer status) { + return ObjUtil.equal(MODEL_DEPLOY_PENDING.status, status); + } + + public static boolean isDisable(Integer status) { + return ObjUtil.equal(MODEL_DEPLOY_RUNNING.status, status); + } + public static boolean isDisable1(Integer status) { + return ObjUtil.equal(MODEL_DEPLOY_SUCCESS.status, status); + } public static boolean isDisable2(Integer status) { + return ObjUtil.equal(MODEL_DEPLOY_FAILED.status, status); + } + + /** + * 根据 name 返回状态值 + * + * @param name 状态名 + * @return 状态值,如果未找到则返回 null + */ + public static Integer getStatusByName(String name) { + for (ModelDeployConstantEnum status : values()) { + if (ObjUtil.equal(status.getName(), name)) { + return status.getStatus(); + } + } + return null; // 如果未找到对应的 name,返回 null + } +} diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/dal/mysql/modelservice/ModelServiceMapper.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/dal/mysql/modelservice/ModelServiceMapper.java index 738ec74f5..c7ffdf794 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/dal/mysql/modelservice/ModelServiceMapper.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/dal/mysql/modelservice/ModelServiceMapper.java @@ -8,6 +8,8 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.llm.dal.dataobject.modelservice.ModelServiceDO; import org.apache.ibatis.annotations.Mapper; import cn.iocoder.yudao.module.llm.controller.admin.modelservice.vo.*; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; /** * 模型服务 Mapper @@ -28,5 +30,6 @@ public interface ModelServiceMapper extends BaseMapperX { .eqIfPresent(ModelServiceDO::getStatus, reqVO.getStatus()) .orderByDesc(ModelServiceDO::getId)); } - + @Update("update llm_model_service set status = #{status} where id = #{id}") + void updateStatus(@Param(value = "id")Long id,@Param(value = "status") Integer status); } diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/handler/AigcCustomDateTimeDeserializer.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/handler/AigcCustomDateTimeDeserializer.java new file mode 100644 index 000000000..7ec000885 --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/handler/AigcCustomDateTimeDeserializer.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.llm.handler; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +public class AigcCustomDateTimeDeserializer extends JsonDeserializer { + private static final DateTimeFormatter FORMATTER_WITH_SPACE = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private static final DateTimeFormatter FORMATTER_WITH_T = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + + @Override + public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + String dateTimeString = jsonParser.getValueAsString(); + String dateTimeString1 = dateTimeString.replaceAll("\\..*", ""); + try { + return LocalDateTime.parse(dateTimeString1, FORMATTER_WITH_SPACE); + } catch (DateTimeParseException e1) { + try { + return LocalDateTime.parse(dateTimeString1, FORMATTER_WITH_T); + } catch (DateTimeParseException e2) { + throw new RuntimeException("Failed to parse date time string: " + dateTimeString1, e2); + } + } + } +} diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/TrainHttpService.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/TrainHttpService.java index 6d81626ac..8c045a807 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/TrainHttpService.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/TrainHttpService.java @@ -159,8 +159,9 @@ public class TrainHttpService { * 根据表名称查询数据 */ public String modelTableQuery(Map headers, String tableName,String query){ - String url = llmBackendProperties.getTableDataQuery(); - String res = HttpUtils.getBody(String.format(url,tableName), headers, query); + String url = String.format(llmBackendProperties.getTableDataQuery(),tableName); + url = url+query; + String res = HttpUtils.get(url, headers); log.info(" model query info :{}", res); return res; diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcModelDeployVO.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcModelDeployVO.java new file mode 100644 index 000000000..b57762bf0 --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcModelDeployVO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.llm.service.http.vo; + +import cn.hutool.core.date.DateTime; +import cn.iocoder.yudao.module.llm.handler.AigcCustomDateTimeDeserializer; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AigcModelDeployVO { + /* + { + "updated_at": "2025-01-09 13:32:10.8013027+00:00", + "model_id": 2, + "created_at": "2025-01-09 13:32:10.8013027+00:00", + "status": "pending", + "inferred_type": "cpu", + "gpu": 0, + "quantization": "float16", + "deployment_name": "test-2", + "deleted_at": "2025-01-09 13:32:18.705719834+00:00", + "id": 4, + "model_path": "/data/base-model/test", + "replicas": 1, + "label": "cpu-aigc-model", + "cpu": 1, + "vllm": 0 + }*/ + @JsonProperty("updated_at") +// @JsonDeserialize(using = AigcCustomDateTimeDeserializer.class) + private LocalDateTime updatedAt; + @JsonProperty("model_id") + private Integer modeId; + @JsonProperty("created_at") +// @JsonDeserialize(using = AigcCustomDateTimeDeserializer.class) + private LocalDateTime createdAt; + private String status; + @JsonProperty("inferred_type") + private String inferredType; + private Integer gpu; + private String quantization; + @JsonProperty("deployment_name") + private String deploymentName; + @JsonProperty("deleted_at") +// @JsonDeserialize(using = AigcCustomDateTimeDeserializer.class) + private LocalDateTime deletedAt; + private Integer id; + @JsonProperty("model_path") + private String modelPath; + private Integer replicas; + private String label; + private Integer cpu; + private Integer vllm; +} diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/modelservice/ModelServiceTaskSyncService.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/modelservice/ModelServiceTaskSyncService.java new file mode 100644 index 000000000..429da3054 --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/modelservice/ModelServiceTaskSyncService.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.llm.service.modelservice; + +import cn.hutool.json.JSONObject; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.llm.controller.admin.dataset.dto.DataJsonTemplate; +import cn.iocoder.yudao.module.llm.dal.dataobject.modelservice.ModelServiceDO; +import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper; +import cn.iocoder.yudao.module.llm.enums.ModelDeployConstantEnum; +import cn.iocoder.yudao.module.llm.handler.AigcCustomDateTimeDeserializer; +import cn.iocoder.yudao.module.llm.service.http.TrainHttpService; +import cn.iocoder.yudao.module.llm.service.http.vo.AigcModelDeployVO; +import cn.iocoder.yudao.module.llm.service.http.vo.AigcRespVO; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.esotericsoftware.kryo.serializers.TimeSerializers; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + + +import javax.annotation.Resource; +import java.net.URLEncoder; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + + +@Component +@Slf4j +public class ModelServiceTaskSyncService { + @Resource + private TrainHttpService trainHttpService; + @Resource + private ModelServiceMapper modelServiceMapper; + + + + @Scheduled(cron ="5 * * * * ?") + public void syncStatusModels() { + log.info("ModelServiceTaskSync 定时任务启动"); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(ModelServiceDO::getStatus, 1); + List modelServiceList = modelServiceMapper.selectList(wrapper); + if (!CollectionUtils.isAnyEmpty(modelServiceList)){ + modelServiceList.forEach(modelServiceDO -> { + Long jobid = modelServiceDO.getJobId(); + if (jobid == null){ + return; + } + + + // 使用 TypeReference 解析 JSON 字符串为 List + try { + String query = "?filter={\"model_id\":"+modelServiceDO.getJobId()+"}"; + String res = trainHttpService.modelTableQuery(new HashMap<>(), "model_deploy",query); + log.info("获取 aigc model_deploy 表数据 info {}",res); + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new JavaTimeModule()); + SimpleModule module = new SimpleModule(); + module.addDeserializer(LocalDateTime.class, new AigcCustomDateTimeDeserializer()); + mapper.registerModule(module); + List aigcModelDeployVOS = mapper.readValue(res,new TypeReference>() {}); + Collections.sort(aigcModelDeployVOS, Comparator.comparing(AigcModelDeployVO::getUpdatedAt).reversed()); + // 获取最新的一条记录 + if (!aigcModelDeployVOS.isEmpty()) { + AigcModelDeployVO latestRecord = aigcModelDeployVOS.get(0); + modelServiceMapper.updateStatus(modelServiceDO.getId(), ModelDeployConstantEnum.getStatusByName(latestRecord.getStatus())); + log.info("最新的 aigcModelDeployVO: {}", latestRecord); + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + + }); + } + log.info("ModelServiceTaskSync 定时任务结束"); + } +}