Merge remote-tracking branch 'origin/master'

This commit is contained in:
leon 2025-02-26 20:18:53 +08:00
commit 7bdba8713b
14 changed files with 411 additions and 176 deletions

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.llm.service.async;
import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.llm.controller.admin.dataset.vo.DatasetQuestionRespVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.dataset.DatasetDO;
@ -8,7 +7,6 @@ import cn.iocoder.yudao.module.llm.dal.mysql.dataset.DatasetMapper;
import cn.iocoder.yudao.module.llm.service.dataset.vo.AigcDatasetVo;
import cn.iocoder.yudao.module.llm.service.http.TrainHttpService;
import cn.iocoder.yudao.module.llm.service.http.vo.AigcDatasetFileRespV0;
import cn.iocoder.yudao.module.llm.service.http.vo.ModelCompletionsReqVO;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
@ -33,15 +31,15 @@ public class AsyncDataSetService {
private static final Logger log = LoggerFactory.getLogger(AsyncKnowledgeBase.class);
@Async
public void JsonFileWrite(DatasetDO datasetDO,List<DatasetQuestionRespVO> datasetQuestionList) {
public void JsonFileWrite (DatasetDO datasetDO, List<DatasetQuestionRespVO> datasetQuestionList) {
List<AigcDatasetVo> aigcDatasetVoList = new ArrayList<>();
datasetQuestionList.forEach(dataSource -> {
AigcDatasetVo aigcDatasetVo = new AigcDatasetVo();
aigcDatasetVo.setInstruction(StringUtils.isNotBlank(dataSource.getSystem())?dataSource.getSystem():"");
aigcDatasetVo.setInput(StringUtils.isNotBlank(dataSource.getQuestion())?dataSource.getQuestion():"");
if (!CollectionUtils.isAnyEmpty(dataSource.getDatasetAnswerRespVO())){
aigcDatasetVo.setOutput(StringUtils.isNotBlank(dataSource.getDatasetAnswerRespVO().get(0).getAnswer())?dataSource.getDatasetAnswerRespVO().get(0).getAnswer():"");
}else {
aigcDatasetVo.setInstruction(StringUtils.isNotBlank(dataSource.getSystem()) ? dataSource.getSystem() : "");
aigcDatasetVo.setInput(StringUtils.isNotBlank(dataSource.getQuestion()) ? dataSource.getQuestion() : "");
if (!CollectionUtils.isAnyEmpty(dataSource.getDatasetAnswerRespVO())) {
aigcDatasetVo.setOutput(StringUtils.isNotBlank(dataSource.getDatasetAnswerRespVO().get(0).getAnswer()) ? dataSource.getDatasetAnswerRespVO().get(0).getAnswer() : "");
} else {
aigcDatasetVo.setOutput("");
}
aigcDatasetVoList.add(aigcDatasetVo);
@ -54,16 +52,16 @@ public class AsyncDataSetService {
sb.append(json).append("\n"); // 每个 JSON 对象后换行
}
InputStream inputStream = new ByteArrayInputStream(sb.toString().getBytes());
AigcDatasetFileRespV0 aigcDatasetFileRespV0 = trainHttpService.AigcUploadFile(new HashMap<>(),"http://36.103.199.104:5123", inputStream, datasetDO.getDatasetName() + "new"+datasetDO.getId() + ".json");
if (aigcDatasetFileRespV0 != null){
datasetMapper.setJobid(datasetDO.getId(),aigcDatasetFileRespV0.getFileId());
AigcDatasetFileRespV0 aigcDatasetFileRespV0 = trainHttpService.AigcUploadFile(new HashMap<>(), "http://36.103.199.104:5123", inputStream, datasetDO.getDatasetName() + "new" + datasetDO.getId() + ".json");
if (aigcDatasetFileRespV0 != null) {
datasetMapper.setJobid(datasetDO.getId(), aigcDatasetFileRespV0.getFileId());
String s3Url = aigcDatasetFileRespV0.getS3Url();
int lastIndex = s3Url.lastIndexOf("/storage");
//todo 1111
String url = s3Url.substring(lastIndex + 1);
datasetMapper.setUrl(datasetDO.getId(),url);
datasetMapper.setUrl(datasetDO.getId(), url);
log.info("[JsonFileWrite][写入文件成功]");
}
@ -74,45 +72,92 @@ public class AsyncDataSetService {
}
public String JsonFileWriteFine(String hostUrl,DatasetDO datasetDO,List<DatasetQuestionRespVO> datasetQuestionList) {
List<AigcDatasetVo> aigcDatasetVoList = new ArrayList<>();
datasetQuestionList.forEach(dataSource -> {
AigcDatasetVo aigcDatasetVo = new AigcDatasetVo();
aigcDatasetVo.setInstruction(StringUtils.isNotBlank(dataSource.getSystem())?dataSource.getSystem():"");
aigcDatasetVo.setInput(StringUtils.isNotBlank(dataSource.getQuestion())?dataSource.getQuestion():"");
if (!CollectionUtils.isAnyEmpty(dataSource.getDatasetAnswerRespVO())){
aigcDatasetVo.setOutput(StringUtils.isNotBlank(dataSource.getDatasetAnswerRespVO().get(0).getAnswer())?dataSource.getDatasetAnswerRespVO().get(0).getAnswer():"");
}else {
aigcDatasetVo.setOutput("");
}
aigcDatasetVoList.add(aigcDatasetVo);
});
ObjectMapper mapper = new ObjectMapper();
StringBuilder sb = new StringBuilder();
public String JsonFileWriteFine (String hostUrl, DatasetDO datasetDO, List<DatasetQuestionRespVO> datasetQuestionList) {
try {
log.info("开始生成 JSON 文件并上传数据集ID: {}", datasetDO.getId());
// 构建 AigcDatasetVo 列表
log.debug("正在构建 AigcDatasetVo 列表...");
List<AigcDatasetVo> aigcDatasetVoList = new ArrayList<>();
for (DatasetQuestionRespVO dataSource : datasetQuestionList) {
AigcDatasetVo aigcDatasetVo = new AigcDatasetVo();
aigcDatasetVo.setInstruction(StringUtils.isNotBlank(dataSource.getSystem()) ? dataSource.getSystem() : "");
aigcDatasetVo.setInput(StringUtils.isNotBlank(dataSource.getQuestion()) ? dataSource.getQuestion() : "");
// 检查答案列表是否为空
if (!CollectionUtils.isAnyEmpty(dataSource.getDatasetAnswerRespVO())) {
aigcDatasetVo.setOutput(StringUtils.isNotBlank(dataSource.getDatasetAnswerRespVO().get(0).getAnswer()) ?
dataSource.getDatasetAnswerRespVO().get(0).getAnswer() : "");
} else {
aigcDatasetVo.setOutput("");
}
aigcDatasetVoList.add(aigcDatasetVo);
}
log.debug("AigcDatasetVo 列表构建完成。记录数量: {}", aigcDatasetVoList.size());
// AigcDatasetVo 列表转换为 JSON 字符串
log.debug("正在将 AigcDatasetVo 列表转换为 JSON 字符串...");
ObjectMapper mapper = new ObjectMapper();
StringBuilder sb = new StringBuilder();
for (AigcDatasetVo aigcDatasetVo : aigcDatasetVoList) {
String json = mapper.writeValueAsString(aigcDatasetVo);
sb.append(json).append("\n"); // 每个 JSON 对象后换行
sb.append(json).append("\n");
}
// JSON 字符串转换为输入流
log.debug("正在将 JSON 字符串转换为输入流...");
InputStream inputStream = new ByteArrayInputStream(sb.toString().getBytes());
AigcDatasetFileRespV0 aigcDatasetFileRespV0 = trainHttpService.AigcUploadFile(new HashMap<>(),hostUrl, inputStream, datasetDO.getDatasetName() + "new"+datasetDO.getId() + ".json");
if (aigcDatasetFileRespV0 != null){
datasetMapper.setJobid(datasetDO.getId(),aigcDatasetFileRespV0.getFileId());
// 上传文件
log.info("正在上传 JSON 文件...");
String fileName = datasetDO.getDatasetName() + "new" + datasetDO.getId() + ".json";
AigcDatasetFileRespV0 aigcDatasetFileRespV0 = trainHttpService.AigcUploadFile(new HashMap<>(), hostUrl, inputStream, fileName);
if (aigcDatasetFileRespV0 != null) {
log.debug("文件上传成功。文件ID: {}", aigcDatasetFileRespV0.getFileId());
// 更新数据集的 Job ID
log.debug("正在更新数据集的 Job ID...");
datasetMapper.setJobid(datasetDO.getId(), aigcDatasetFileRespV0.getFileId());
log.info("hostUrl:{}", hostUrl);
// 更新数据集的 URL
String s3Url = aigcDatasetFileRespV0.getS3Url();
int lastIndex = s3Url.lastIndexOf("/storage");
log.info("s3Url:{}", s3Url);
// int lastIndex = s3Url.lastIndexOf("/storage");
// String url = s3Url.substring(lastIndex + 1);
// log.info("url:{}", url);
// 找到 "/uploads" 的位置
int uploadsIndex = s3Url.indexOf("/uploads");
if (uploadsIndex == -1) {
log.error("s3Url 中未找到 '/uploads' 路径");
return "";
}
// 提取 "/uploads" 及之后的部分
String uploadsPath = s3Url.substring(uploadsIndex);
log.info("uploadsPath: {}", uploadsPath);
// 构建新的完整 URL
String newUrl = hostUrl + uploadsPath;
log.info("newUrl: {}", newUrl);
datasetMapper.setUrl(datasetDO.getId(), newUrl);
// 返回结果
String result = newUrl.substring(hostUrl.length());
log.info("JSON 文件生成并上传成功。返回结果: {}", result);
//todo 1111
String url = s3Url.substring(lastIndex + 1);
datasetMapper.setUrl(datasetDO.getId(),url);
String result = url.substring(hostUrl.length());
log.info("[JsonFileWrite][写入文件成功]");
return result;
} else {
log.error("文件上传失败。数据集ID: {}", datasetDO.getId());
return "";
}
} catch (IOException e) {
// 记录异常信息
log.error("[JsonFileWrite][写入文件失败] {}", e.getMessage());
log.error("生成或上传 JSON 文件时发生异常。数据集ID: {}", datasetDO.getId(), e);
return "";
}
return "";
}
}

View File

@ -133,7 +133,7 @@ public class AsyncFineTuningTaskService {
updateObj.setStatus(FinetuningTaskStatusEnum.WAITING.getStatus());
updateObj.setJobModelName(resp.getFineTunedModel());
updateObj.setTrainLog(resp.getTrainLog());
log.info("微调任务创建成功。任务ID: {}, 任务模型名称: {} , 任务状态: {}", fineTuningTask.getId(), fineTuningTask.getJobModelName(),FinetuningTaskStatusEnum.WAITING.getStatus());
log.info("微调任务创建成功。任务ID: {}, 任务模型名称: {} , 任务状态: {}", fineTuningTask.getId(), resp.getFineTunedModel(), FinetuningTaskStatusEnum.WAITING.getStatus());
} else {
updateObj.setStatus(FinetuningTaskStatusEnum.FAILED.getStatus());
log.error("微调任务创建失败。任务ID: {}", fineTuningTask.getId());
@ -146,7 +146,7 @@ public class AsyncFineTuningTaskService {
} catch (Exception e) {
log.error("创建微调任务时发生异常。任务ID: {}", fineTuningTask.getId(), e);
e.printStackTrace();
throw e;
}
}
@ -177,7 +177,9 @@ public class AsyncFineTuningTaskService {
AigcFineTuningCreateReqVO req = new AigcFineTuningCreateReqVO();
req.setModel(fineTuningTask.getBaseModel());
req.setTrainEpoch((fineTuningTask.getEpoch() == 0) ? 1 : fineTuningTask.getEpoch());
req.setTrainEpoch((fineTuningTask.getSaveSteps() == 0) ? 1 : fineTuningTask.getSaveSteps());
int saveStep = Optional.ofNullable(fineTuningTask.getSaveSteps())
.orElse(0) + 1;
req.setTrainEpoch(saveStep);
req.setSuffix(fineTuningTask.getTaskName());
req.setRemark(fineTuningTask.getTaskIntro());
req.setTrainBatchSize(fineTuningTask.getBatchSize());
@ -194,7 +196,7 @@ public class AsyncFineTuningTaskService {
@Async
public void startFineTuningTask (FineTuningTaskDO fineTuningTask) {
log.info(" ===== 开始微调任务 ===== stopFinetuning");
String modelName = fineTuningTask.getJobModelName()+"-"+fineTuningTask.getDeployCount()+1;
String modelName = fineTuningTask.getJobModelName() + "-" + fineTuningTask.getDeployCount() + 1;
try {
log.info("开始调用HTTP服务开始微调任务任务模型名称: {}", modelName);
createTuning(fineTuningTask);

View File

@ -75,14 +75,14 @@ public class AsyncKnowledgeBase {
if (lastIndex != -1) {
String extension = knowledge.getDocumentName().substring(lastIndex + 1).toLowerCase();
log.info("文档扩展名: {}", extension);
if ("txt".equals(extension)) {
log.info("文档为 txt 文件,直接上传嵌入,文档 ID: {}", knowledge.getId());
ragHttpService.embedUploadFile(regUploadReqVO);
} else {
log.info("文档为非 txt 文件,调用知识嵌入方法,文档 ID: {}", knowledge.getId());
knowledgeEmbed(knowledge, knowledge.getKnowledgeBaseId());
}
knowledgeEmbed(knowledge, knowledge.getKnowledgeBaseId());
// if ("txt".equals(extension)) {
// log.info("文档为 txt 文件,直接上传嵌入,文档 ID: {}", knowledge.getId());
// ragHttpService.embedUploadFile(regUploadReqVO);
// } else {
// log.info("文档为非 txt 文件,调用知识嵌入方法,文档 ID: {}", knowledge.getId());
// knowledgeEmbed(knowledge, knowledge.getKnowledgeBaseId());
// }
} else {
log.warn("文档无扩展名,跳过处理,文档 ID: {}", knowledge.getId());
}

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.servername.ServerNameMapper;
import cn.iocoder.yudao.module.llm.service.http.TrainHttpService;
import cn.iocoder.yudao.module.llm.service.http.vo.*;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
@ -80,29 +81,90 @@ public class AsyncModelServiceService {
//模型服务开启
@Async
public void startModelService(ModelServiceDO updateObj) {
// try {
// ModelServiceDO modelServiceDO = modelServiceMapper.selectById(updateObj.getId());
// ServerNameDO serverNameDO = serverNameMapper.selectById(modelServiceDO.getGpuType());
// if (modelServiceDO.getJobId() != null){
// AigcModelDeployVO modelDeployVO = trainHttpService.modelUndeploy(new HashMap<>(),serverNameDO.getHost(), modelServiceDO.getJobId());
// }
// AigcModelDeploySaveReq aigcModelDeploySaveReq = new AigcModelDeploySaveReq(modelServiceDO.getBaseModelName(),
// "gpu");
// ModelDeployRespVO modelDeployRespVO = trainHttpService.modelDeploy(new HashMap<>(),serverNameDO.getHost(), aigcModelDeploySaveReq);
// log.info("modelDeploy info {}",modelDeployRespVO);
// if (modelDeployRespVO.getMessage().equals("error")){
// updateObj.setStatus(3);
// }else {
// updateObj.setStatus(1);
// updateObj.setJobId(modelDeployRespVO.getId());
// updateObj.setModelUrl(modelDeployRespVO.getPort()+DEFAULT_MODEL_URL_SUFFIX);
// }
//
// modelServiceMapper.updateById(updateObj);
// }catch(Exception e){
//// updateObj.setStatus(3);
// modelServiceMapper.updateById(updateObj);
// };
try {
log.info("开始启动模型服务服务ID: {}", updateObj.getId());
// 查询模型服务信息
log.info("正在查询模型服务信息服务ID: {}", updateObj.getId());
ModelServiceDO modelServiceDO = modelServiceMapper.selectById(updateObj.getId());
ServerNameDO serverNameDO = serverNameMapper.selectById(modelServiceDO.getGpuType());
if (modelServiceDO.getJobId() != null){
AigcModelDeployVO modelDeployVO = trainHttpService.modelUndeploy(new HashMap<>(),serverNameDO.getHost(), modelServiceDO.getJobId());
if (modelServiceDO == null) {
log.error("未找到模型服务信息服务ID: {}", updateObj.getId());
throw new RuntimeException("模型服务信息不存在");
}
AigcModelDeploySaveReq aigcModelDeploySaveReq = new AigcModelDeploySaveReq(modelServiceDO.getBaseModelName(),
"gpu");
ModelDeployRespVO modelDeployRespVO = trainHttpService.modelDeploy(new HashMap<>(),serverNameDO.getHost(), aigcModelDeploySaveReq);
log.info("modelDeploy info {}",modelDeployRespVO);
if (modelDeployRespVO.getMessage().equals("error")){
updateObj.setStatus(3);
}else {
updateObj.setStatus(1);
updateObj.setJobId(modelDeployRespVO.getId());
updateObj.setModelUrl(modelDeployRespVO.getPort()+DEFAULT_MODEL_URL_SUFFIX);
log.info("模型服务信息查询成功。服务名称: {}", modelServiceDO.getBaseModelName());
// 查询 GPU 服务器信息
log.info("正在查询 GPU 服务器信息GPU 类型: {}", modelServiceDO.getGpuType());
ServerNameDO serverNameDO = serverNameMapper.selectById(modelServiceDO.getGpuType());
if (serverNameDO == null) {
log.error("未找到 GPU 服务器信息GPU 类型: {}", modelServiceDO.getGpuType());
throw new RuntimeException("GPU 服务器信息不存在");
}
log.info("GPU 服务器信息查询成功。主机地址: {}", serverNameDO.getHost());
// 如果已有任务 ID则先卸载模型
if (modelServiceDO.getJobId() != null) {
log.info("检测到已有任务 ID正在卸载模型任务ID: {}", modelServiceDO.getJobId());
AigcModelDeployVO modelDeployVO = trainHttpService.modelUndeploy(new HashMap<>(), serverNameDO.getHost(), modelServiceDO.getJobId());
log.info("模型卸载完成。卸载结果: {}", JSON.toJSONString(modelDeployVO));
}
// 构建模型部署请求
log.debug("正在构建模型部署请求...");
AigcModelDeploySaveReq aigcModelDeploySaveReq = new AigcModelDeploySaveReq(
modelServiceDO.getBaseModelName(), "gpu");
log.debug("模型部署请求参数: {}", JSON.toJSONString(aigcModelDeploySaveReq));
// 发起模型部署请求
log.info("正在发起模型部署请求...");
ModelDeployRespVO modelDeployRespVO = trainHttpService.modelDeploy(new HashMap<>(), serverNameDO.getHost(), aigcModelDeploySaveReq);
log.info("模型部署请求完成。部署结果: {}", JSON.toJSONString(modelDeployRespVO));
// 更新模型服务状态
if ("error".equals(modelDeployRespVO.getMessage())) {
log.error("模型部署失败。服务ID: {}", updateObj.getId());
updateObj.setStatus(3);
} else {
log.info("模型部署成功。服务ID: {}", updateObj.getId());
updateObj.setStatus(1);
updateObj.setJobId(modelDeployRespVO.getId());
updateObj.setModelUrl(modelDeployRespVO.getPort() + DEFAULT_MODEL_URL_SUFFIX);
}
// 更新数据库
log.info("正在更新数据库中的模型服务状态...");
modelServiceMapper.updateById(updateObj);
}catch(Exception e){
// updateObj.setStatus(3);
log.info("数据库更新完成。服务ID: {}", updateObj.getId());
} catch (Exception e) {
log.error("启动模型服务时发生异常。服务ID: {}", updateObj.getId(), e);
updateObj.setStatus(3);
modelServiceMapper.updateById(updateObj);
};
}
}
//调型服务关闭

View File

@ -4,9 +4,9 @@ import cn.iocoder.yudao.module.llm.controller.admin.basemodel.vo.BaseModelSaveRe
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.servername.ServerNameDO;
import cn.iocoder.yudao.module.llm.dal.mysql.servername.ServerNameMapper;
import cn.iocoder.yudao.module.llm.enums.ModelDeployConstantEnum;
import cn.iocoder.yudao.module.llm.handler.AigcCustomDateTimeDeserializer;
import cn.iocoder.yudao.module.llm.service.basemodel.vo.ModelListRes;
import cn.iocoder.yudao.module.llm.service.http.FineTuningTaskHttpService;
import cn.iocoder.yudao.module.llm.service.http.TrainHttpService;
import cn.iocoder.yudao.module.llm.service.http.vo.AigcModelDeploySaveReq;
import cn.iocoder.yudao.module.llm.service.http.vo.AigcModelDeployVO;
@ -43,7 +43,11 @@ public class BaseModelTaskService {
@Resource
ServerNameMapper serverNameMapper;
@Resource
private FineTuningTaskHttpService fineTuningTaskHttpService;
private static final String DEFAULT_MODEL_URL_SUFFIX = "/v1/chat/completions";
// 减少维护 先注释掉
@Scheduled(cron ="0 0/1 * * * ?")
public void synchronous() throws JsonProcessingException {
@ -73,7 +77,7 @@ public class BaseModelTaskService {
// 构建查询参数并查询模型部署信息
String query = "?filter={\"id\":" + modelId + "}";
log.debug("正在查询模型部署信息,查询参数: {}", query);
String res = trainHttpService.modelTableQuery(new HashMap<>(), serverName.getHost(), "model_deploy", query);
String res = fineTuningTaskHttpService.modelTableQuery(new HashMap<>(), serverName.getHost(), "model_deploy", query);
log.debug("模型部署信息查询成功。响应内容: {}", res);
// 解析响应内容

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.llm.service.finetuningtask;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.llm.dal.dataobject.finetuningtask.FineTuningTaskDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.servername.ServerNameDO;
import cn.iocoder.yudao.module.llm.dal.mysql.finetuningtask.FineTuningTaskMapper;
@ -7,6 +8,7 @@ import cn.iocoder.yudao.module.llm.dal.mysql.servername.ServerNameMapper;
import cn.iocoder.yudao.module.llm.enums.FineTuningTaskStatusConstants;
import cn.iocoder.yudao.module.llm.enums.FinetuningTaskStatusEnum;
import cn.iocoder.yudao.module.llm.service.basemodel.vo.ModelListRes;
import cn.iocoder.yudao.module.llm.service.http.FineTuningTaskHttpService;
import cn.iocoder.yudao.module.llm.service.http.TrainHttpService;
import cn.iocoder.yudao.module.llm.service.http.vo.AigcFineTuningDetailRespVO;
import cn.iocoder.yudao.module.llm.service.http.vo.AigcModelDeployVO;
@ -40,9 +42,13 @@ public class FineTuningTaskSyncService {
@Resource
FineTuningTaskMapper fineTuningTaskMapper;
@Resource
ServerNameMapper serverNameMapper;
@Resource
private FineTuningTaskHttpService fineTuningTaskHttpService;
@Scheduled(cron = "0 */1 * * * ?")
public void updateFineTuningTaskStatus() {
Log.info("FineTuningTaskSync 定时任务启动");
@ -57,7 +63,7 @@ public class FineTuningTaskSyncService {
}
String hostUrl = serverNameDO!=null ?serverNameDO.getHost():"";
String queryJobs = "?filter={\"job_id\":\""+fineTuningTaskDO.getJobId()+"\"}";
String respJobs = trainHttpService.modelTableQuery(new HashMap<>(), hostUrl,"fine_tuning_train_job",queryJobs);
String respJobs = fineTuningTaskHttpService.modelTableQuery(new HashMap<>(), hostUrl,"fine_tuning_train_job",queryJobs);
AigcFineTuningDetailRespVO resp = new AigcFineTuningDetailRespVO();
try {
ObjectMapper mapper = new ObjectMapper();
@ -74,6 +80,9 @@ public class FineTuningTaskSyncService {
continue;
}
FineTuningTaskDO updateObj = new FineTuningTaskDO();
if (ObjectUtil.isAllEmpty(resp.getTrain_status())){
continue;
}
Integer status = FineTuningTaskStatusConstants.getStatus(resp.getTrain_status());
if(status != null){
updateObj.setId(fineTuningTaskDO.getId());
@ -109,7 +118,7 @@ public class FineTuningTaskSyncService {
updateObj.setStatus(2);
// 获取模型id
String querModels = "?filter={\"model_name\":\""+resp.getFine_tuned_model()+"\"}";
String resModels = trainHttpService.modelTableQuery(new HashMap<>(),hostUrl, "models",querModels);
String resModels = fineTuningTaskHttpService.modelTableQuery(new HashMap<>(),hostUrl, "models",querModels);
log.info("获取 aigc models 表数据 info {}",resModels);
JSONArray jsonArrayModels = JSONArray.parseArray(resModels);

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.llm.service.http;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.module.llm.dal.dataobject.finetuningtask.FineTuningTaskDO;
import cn.iocoder.yudao.module.llm.framework.backend.config.LLMBackendProperties;
@ -16,10 +17,15 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/**
* @Description 微调任务相关接口
*/
@ -88,16 +94,16 @@ public class FineTuningTaskHttpService {
// TODO: 在上个方法中已经将数据集的文件id赋予调试时需要写死再放开
// String fileId = "6237ed4d-a046-479c-80d6-8579a0283994";
// req.setFileId(fileId);
String requestUrl = url + llmBackendProperties.getFinetuningCreate();
try {
// 记录请求信息
log.info("开始创建微调任务请求URL: {}", url + llmBackendProperties.getFinetuningCreate());
log.info("开始创建微调任务请求URL: {}", requestUrl);
log.info("请求头: {}", headers);
log.info("请求体: {}", JSON.toJSONString(req));
// 发起 HTTP 请求
log.debug("正在发起 HTTP POST 请求...");
String res = HttpUtils.post(url + llmBackendProperties.getFinetuningCreate(), headers, JSON.toJSONString(req));
String res = HttpUtils.post(requestUrl, headers, JSON.toJSONString(req));
log.info("HTTP 请求完成。响应内容: {}", res);
// 解析响应
@ -110,8 +116,56 @@ public class FineTuningTaskHttpService {
return aigcFineTuningCreateRespVO;
} catch (Exception e) {
log.error("创建微调任务时发生异常。请求URL: {}", url + llmBackendProperties.getFinetuningCreate(), e);
throw new RuntimeException("微调任务创建失败", e);
log.error("创建微调任务时发生异常。请求URL: {}", requestUrl, e);
handleHttpException(e);
}
return null;
}
/**
* 根据表名称查询数据
*/
public String modelTableQuery(Map<String, String> headers, String urlHost, String tableName, String query) {
// 构建完整请求 URL
String url = String.format(urlHost + llmBackendProperties.getTableDataQuery(), tableName);
url = url + query;
try {
// 记录请求信息
log.info("开始查询模型表数据请求URL: {}", url);
// 发起 HTTP GET 请求
String response = HttpUtils.get(url, headers);
log.info("HTTP 请求完成。响应内容: {}", response);
// 返回响应数据
return response;
} catch (Exception e) {
log.error("查询模型表数据时发生异常。请求URL: {}", url, e);
handleHttpException(e);
}
return "";
}
/**
* 统一处理 HTTP 请求异常
*/
private void handleHttpException(Exception e) {
if (e instanceof ConnectException||StringUtils.contains(e.getMessage(), "Connection refused")) {
log.error("连接算法服务失败,请检查算法服务是否正常。");
throw exception(HTTP_CONNECTION_REFUSED);
} else if (e instanceof SocketTimeoutException || StringUtils.contains(e.getMessage(), "connect timed out")) {
log.error("连接算法服务超时,请检查网络或算法服务是否正常。");
throw exception(HTTP_CONNECTION_TIMEOUT);
} else if (e instanceof IOException) {
log.error("HTTP 请求发生 IO 异常: {}", e.getMessage());
throw exception(HTTP_IO_ERROR);
} else {
log.error("未知异常: {}", e.getMessage());
throw new RuntimeException("HTTP 请求发生未知异常", e);
}
}
}

View File

@ -65,41 +65,68 @@ public class ModelService {
* @return
*/
public ModelCompletionsRespVO modelCompletions (String url, ModelCompletionsReqVO req) {
if (StringUtils.isBlank(req.getModel())) {
req.setModel(DEFAULT_MODEL_ID);
}
log.info("request: {}", req);
String result;
if (StringUtils.isBlank(url)) {
log.info("url1: {}", llmBackendProperties.getModelCompletions());
result = HttpUtils.post(llmBackendProperties.getModelCompletions(), null, JSON.toJSONString(req));
} else {
log.info("url2: {}", url);
result = HttpUtils.post(url, null, JSON.toJSONString(req));
}
log.info("11 response: {}", result);
if (StringUtils.isBlank(result)) {
return null;
}
try {
log.info("开始处理模型补全请求...");
// 检查模型是否为空若为空则设置默认模型
if (StringUtils.isBlank(req.getModel())) {
log.debug("模型ID为空设置为默认模型: {}", DEFAULT_MODEL_ID);
req.setModel(DEFAULT_MODEL_ID);
}
// 记录请求信息
log.info("请求参数: {}", JSON.toJSONString(req));
// 发起 HTTP POST 请求
String result;
if (StringUtils.isBlank(url)) {
log.info("URL为空使用默认URL: {}", llmBackendProperties.getModelCompletions());
result = HttpUtils.post(llmBackendProperties.getModelCompletions(), null, JSON.toJSONString(req));
} else {
log.info("使用指定URL: {}", url);
result = HttpUtils.post(url, null, JSON.toJSONString(req));
}
log.info("HTTP 请求完成。响应内容: {}", result);
// 检查响应是否为空
if (StringUtils.isBlank(result)) {
log.warn("响应内容为空,返回 null");
return null;
}
// 解析响应内容
log.info("正在解析响应内容...");
ChatCompletion chatCompletion = JSON.parseObject(result, ChatCompletion.class);
// 检查响应内容是否包含错误信息
if (StringUtils.isBlank(chatCompletion.getDetail())) {
log.info("响应内容无错误信息,提取回答内容...");
// 提取回答内容
String respContent = chatCompletion.getChoices().get(0).getMessage().getContent();
String patternString = "(<think>.*?</think>)";
Pattern pattern = Pattern.compile(patternString, Pattern.DOTALL);
Matcher matcher = pattern.matcher(respContent);
String answerContent = matcher.replaceAll("");
// 没有detail就是没有错误
// 构建返回对象
ModelCompletionsRespVO respVO = new ModelCompletionsRespVO();
respVO.setSystem("助手");
respVO.setQuestion(req.getMessages().get(req.getMessages().size() - 1).getContent());
respVO.setAnswer(answerContent);
log.info("模型补全请求处理成功。返回结果: {}", JSON.toJSONString(respVO));
return respVO;
} else {
log.warn("响应内容包含错误信息,返回 null");
return null;
}
return null;
} catch (Exception e) {
throw new RuntimeException(e);
log.error("处理模型补全请求时发生异常。", e);
throw new RuntimeException("模型补全请求处理失败", e);
}
}
@ -144,7 +171,7 @@ public class ModelService {
ServerNameDO server = getServerByType(gpuType);
String baseUrl = server.getHost();
if (baseUrl == null || baseUrl.trim().isEmpty()) {
log.warn("GPU: Type: {} , Name: {} , Host: {}", gpuType, server.getCardServerName(), baseUrl);
log.info("GPU: Type: {} , Name: {} , Host: {}", gpuType, server.getCardServerName(), baseUrl);
return Collections.emptyList();
}

View File

@ -395,11 +395,11 @@ public class RagHttpService {
log.info("成功获取文件字节数组,文件大小: {} 字节", fileBytes.length);
// 创建 OkHttpClient 实例
log.info("创建 OkHttpClient 实例,设置超时时间为 30 分钟");
log.info("创建 OkHttpClient 实例,设置超时时间为 3 分钟");
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.MINUTES)
.readTimeout(30, TimeUnit.MINUTES)
.writeTimeout(30, TimeUnit.MINUTES)
.connectTimeout(3, TimeUnit.MINUTES)
.readTimeout(3, TimeUnit.MINUTES)
.writeTimeout(3, TimeUnit.MINUTES)
.build();
// 创建 MultipartBody

View File

@ -11,17 +11,23 @@ import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import kong.unirest.UnirestException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/**
* 训练相关接口
*/
@ -145,19 +151,6 @@ public class TrainHttpService {
return null;
}
/**
* 根据表名称查询数据
*/
public String modelTableQuery (Map<String, String> headers, String urlHost, String tableName, String query) {
String url = String.format(urlHost + llmBackendProperties.getTableDataQuery(), tableName);
url = url + query;
String res = HttpUtils.get(url, headers);
log.info(" model query info :{}", res);
return res;
}
public AigcFineTuningDetailRespVO finetuningDetail (Map<String, String> headers, String jobId) {
login(headers);
String finetuningDetail = llmBackendProperties.getFinetuningDetail();
@ -228,32 +221,70 @@ public class TrainHttpService {
}
public ModelDeployRespVO modelDeploy (Map<String, String> headers, String url, AigcModelDeploySaveReq req) {
// login(headers);
String modelDeploy = llmBackendProperties.getModelDeploy();
log.info(" modelDeploy request:{}", JSON.toJSONString(req));
String res = HttpUtils.post(url + modelDeploy, headers, JSON.toJSONString(req));
log.info(" modelDeploy:{}", res);
JSONObject parseObject = JSON.parseObject(res);
ModelDeployRespVO modelDeployRespVO = new ModelDeployRespVO();
try {
log.info("开始部署模型请求URL: {}", url + llmBackendProperties.getModelDeploy());
log.info("--- {}", parseObject);
if (parseObject.containsKey("error")) {
modelDeployRespVO.setMessage("error");
// 记录请求参数
log.info("请求参数: {}", JSON.toJSONString(req));
// 发起 HTTP POST 请求
String res = HttpUtils.post(url + llmBackendProperties.getModelDeploy(), headers, JSON.toJSONString(req));
log.info("HTTP 请求完成。响应内容: {}", res);
// 解析响应内容
log.debug("正在解析响应内容...");
JSONObject parseObject = JSON.parseObject(res);
ModelDeployRespVO modelDeployRespVO = new ModelDeployRespVO();
// 检查响应是否包含错误
if (parseObject.containsKey("error")) {
log.error("模型部署失败。响应中包含错误信息: {}", parseObject.getString("error"));
modelDeployRespVO.setMessage("error");
return modelDeployRespVO;
}
// 解析响应为 ModelDeployRespVO 对象
modelDeployRespVO = JSON.parseObject(res.getBytes(), ModelDeployRespVO.class);
log.info("模型部署成功。部署结果: {}", JSON.toJSONString(modelDeployRespVO));
// 返回结果
return modelDeployRespVO;
}
modelDeployRespVO = JSON.parseObject(res.getBytes(), ModelDeployRespVO.class);
return modelDeployRespVO;
} catch (Exception e) {
log.error("部署模型时发生异常。请求URL: {}", url + llmBackendProperties.getModelDeploy(), e);
ModelDeployRespVO errorResp = new ModelDeployRespVO();
errorResp.setMessage("error");
return errorResp;
}
}
public AigcModelDeployVO modelUndeploy (Map<String, String> headers, String url, Long deployId) {
// login(headers);
String modelDeploy = llmBackendProperties.getModelUndeploy();
String res = HttpUtils.post(url + modelDeploy + deployId, headers, "");
log.info(" modelDeploy:{}", res);
AigcModelDeployVO modelDeployRespVO = JSON.parseObject(res, AigcModelDeployVO.class);
log.info(" modelDeploy:{}", modelDeployRespVO);
return modelDeployRespVO;
try {
log.info("开始卸载模型部署部署ID: {}", deployId);
// 构建请求 URL
String modelDeploy = llmBackendProperties.getModelUndeploy();
String requestUrl = url + modelDeploy + deployId;
log.info("构建请求 URL: {}", requestUrl);
// 发起 HTTP POST 请求
log.info("正在发起 HTTP POST 请求...");
String res = HttpUtils.post(requestUrl, headers, "");
log.info("HTTP 请求完成。响应内容: {}", res);
// 解析响应内容
log.info("正在解析响应内容...");
AigcModelDeployVO modelDeployRespVO = JSON.parseObject(res, AigcModelDeployVO.class);
log.info("响应解析完成。模型卸载结果: {}", JSON.toJSONString(modelDeployRespVO));
// 返回结果
return modelDeployRespVO;
} catch (Exception e) {
log.error("卸载模型部署时发生异常。部署ID: {}", deployId, e);
throw new RuntimeException("模型卸载失败", e);
}
}
/**

View File

@ -147,14 +147,22 @@ public class ModelServiceServiceImpl implements ModelServiceService {
public void deleteModelService (Long id) {
// 校验存在
validateModelServiceExists(id);
// 校验使用
validateModelUse(id);
ModelServiceDO modelServiceDO = modelServiceMapper.selectById(id);
ServerNameDO serverNameDO = serverNameService.getServerName(modelServiceDO.getGpuType());
trainHttpService.modelUndeploy(new HashMap<>(), serverNameDO.getHost(),modelServiceDO.getJobId());
// 删除
// 发起模型卸载请求
log.info("正在发起模型卸载请求服务ID: {}", id);
trainHttpService.modelUndeploy(new HashMap<>(), serverNameDO.getHost(), modelServiceDO.getJobId());
log.info("模型卸载请求完成服务ID: {}", id);
// 删除模型服务
log.debug("正在删除模型服务服务ID: {}", id);
modelServiceMapper.deleteById(id);
log.info("模型服务删除成功服务ID: {}", id);
}
/**

View File

@ -1,39 +1,26 @@
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.dataobject.servername.ServerNameDO;
import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.servername.ServerNameMapper;
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.FineTuningTaskHttpService;
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;
@ -41,15 +28,15 @@ import java.util.List;
@Component
@Slf4j
public class ModelServiceTaskSyncService {
@Resource
private TrainHttpService trainHttpService;
@Resource
private ModelServiceMapper modelServiceMapper;
@Resource
ServerNameMapper serverNameMapper;
@Resource
private FineTuningTaskHttpService fineTuningTaskHttpService;
@Scheduled(cron = "0 */2 * * * ?")
public void syncStatusModels() {
@ -70,7 +57,7 @@ public class ModelServiceTaskSyncService {
String query = "?filter={\"id\":"+jobid+"}";
ServerNameDO serverNameDO = serverNameMapper.selectById(modelServiceDO.getGpuType());
String hostUrl = serverNameDO!=null ?serverNameDO.getHost():"";
String res = trainHttpService.modelTableQuery(new HashMap<>(), hostUrl,"model_deploy",query);
String res = fineTuningTaskHttpService.modelTableQuery(new HashMap<>(), hostUrl,"model_deploy",query);
log.info("获取 aigc model_deploy 表数据 info {}",res);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());

View File

@ -163,4 +163,8 @@ public interface ErrorCodeConstants {
// ========== 站内信发送 1-002-028-000 ==========
ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "模板参数({})缺失");
// ========== HTTP 模块错误码 1-003-000-000==========
ErrorCode HTTP_CONNECTION_REFUSED = new ErrorCode(1_003_000_000, "HTTP 请求失败,连接被拒绝");
ErrorCode HTTP_CONNECTION_TIMEOUT = new ErrorCode(1_003_000_001, "HTTP 请求失败,连接超时");
ErrorCode HTTP_IO_ERROR = new ErrorCode(1_003_000_002, "HTTP 请求失败IO 异常");
}

View File

@ -249,23 +249,23 @@ llm:
#################### 8123: RAG服务、训练集和标注相关API。 ###################
### RAG服务
#RAG健康检查 GET
rag_health: http://36.103.199.248:8123/health
rag_health: http://127.0.0.1:8123/health
#上传并向量化 POST
rag_embed: http://36.103.199.248:8123/embed
rag_embed: http://127.0.0.1:8123/embed
#获取所有向量id GET
rag_ids: http://36.103.199.248:8123/ids
rag_ids: http://127.0.0.1:8123/ids
#根据id获取文档 GET
rag_documents: http://36.103.199.248:8123/documents
rag_documents: http://127.0.0.1:8123/documents
#根据id删除文档 DEL
rag_documents_del: http://36.103.199.248:8123/documents
rag_documents_del: http://127.0.0.1:8123/documents
#根据file_id检索向量 POST
rag_query: http://36.103.199.248:8123/query
rag_query: http://127.0.0.1:8123/query
#支持多个文件id查询向量 GET
rag_query_multiple: http://36.103.199.248:8123/query_multiple
rag_query_multiple: http://127.0.0.1:8123/query_multiple
# 知识库向量嵌入
embed: http://36.103.199.248:8123/embed
embed: http://127.0.0.1:8123/embed
# 知识库查询
embed_query: http://36.103.199.248:8123/query
embed_query: http://127.0.0.1:8123/query
#### LLM train and service api 训练集、标注相关API
# 训练集列表 GET
@ -283,26 +283,28 @@ llm:
#################### 9000: 大模型管理、微调任务、文件上传和模型部署相关API。 ###################
# 大模型列表 GET
models_list: http://36.103.199.248:9000/api/models
models_list: http://127.0.0.1:9000/api/models
# 登录 POST
login: http://36.103.199.248:9000/api/auth/login
account: http://36.103.199.248:9000/api/auth/account
login: http://127.0.0.1:9000/api/auth/login
account: http://127.0.0.1:9000/api/auth/account
login_username: admin
login_password: admin
# 微调任务详情 GET
finetuning_detail: http://36.103.199.248:9000/api/finetuning
finetuning_detail: http://127.0.0.1:9000/api/finetuning
# 微调任务取消
finetuning_cancel: http://36.103.199.248:9000/api/finetuning/%s/cancel
finetuning_cancel: http://127.0.0.1:9000/api/finetuning/%s/cancel
# 微调文件列表 GET
finetuning_file_list: http://36.103.199.248:9000/api/files?purpose=fine-tune
finetuning_file_list: http://127.0.0.1:9000/api/files?purpose=fine-tune
# 模型部署
model_create: http://36.103.199.248:9000/api/models
model_create: http://127.0.0.1:9000/api/models
# aigc模型推理
aigc_model_completions: http://36.103.199.248:9000/api/channels/chat/completions
# 微调文件上传
aigc_model_completions: http://127.0.0.1:9000/api/channels/chat/completions
#################### 5123: 微调任务、模型部署、文件管理、提示词优化、自动评估、文生图等API。 ###################
aigc_file_upload: /api/files
# 创建微调任务 POST
# 微调文件上传
aigc_file_upload: /api/files
finetuning_create: /llm/finetuning
# 日志获取
finetuning_log: /llm/get_log
@ -330,9 +332,9 @@ llm:
#################### 30000: 大模型对话相关API。 ###################
#### 大模型对话
# 模型列表 GET
base_model_list: http://36.103.199.248:30000/model/v1/models
base_model_list: http://127.0.0.1:30000/model/v1/models
# 模型对话 POST
model_completions: http://36.103.199.248:30000/v1/chat/completions
model_completions: http://127.0.0.1:30000/v1/chat/completions
#################### 48080: 应用和管理服务相关API。 ###################
application_api: http://localhost:48080/admin-api/llm/application/api/apiKey/chat