feat(project): 实现AI项目初始化及相关实体管理
- 新增通用返回类BaseResponse用于统一接口响应格式 - 新增业务异常BusinessException及全局异常处理GlobalExceptionHandler - 新增OSS文件上传控制器支持文件上传与删除接口 - 添加项目核心实体类Project、ProjectMember、ProjectMilestone、ProjectTimeline和Resource - 实现ProjectService接口及其实现类,使用AI能力从项目文档生成结构化项目数据 - 在ProjectServiceImpl中实现项目数据解析、保存及业务逻辑,包括项目、里程碑、任务、成员、资源、风险等 - 项目初始化控制器ProjectController提供文件上传触发项目初始化功能 - 设计了详细的系统提示词和用户提示词,用于AI模型指导生成严格格式的结构化项目数据 - 设计项目数据持久化流程,确保生成的数据正确保存至数据库,支持事务回滚 - 增强日志记录,便于追踪项目初始化全过程及错误调试
This commit is contained in:
@@ -3,8 +3,6 @@ package cn.yinlihupo.service.project;
|
||||
import cn.yinlihupo.domain.vo.ProjectInitResult;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI项目初始化服务接口
|
||||
* 使用Spring AI结构化输出能力,从项目文档中提取结构化信息
|
||||
@@ -40,8 +38,7 @@ public interface ProjectService {
|
||||
* 根据项目资料内容生成并保存项目初始化数据
|
||||
*
|
||||
* @param content 项目资料文本内容
|
||||
* @param inputFiles 输入文件列表信息
|
||||
* @return 项目初始化结果
|
||||
*/
|
||||
ProjectInitResult generateAndSaveProjectFromContent(String content, List<cn.yinlihupo.domain.entity.ProjectInitRecord.InputFile> inputFiles);
|
||||
ProjectInitResult generateAndSaveProjectFromContent(String content);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ public class ProjectServiceImpl implements ProjectService {
|
||||
private final ResourceMapper resourceMapper;
|
||||
private final RiskMapper riskMapper;
|
||||
private final ProjectTimelineMapper projectTimelineMapper;
|
||||
private final ProjectInitRecordMapper projectInitRecordMapper;
|
||||
|
||||
/**
|
||||
* 项目初始化系统提示词模板
|
||||
@@ -214,17 +213,8 @@ public class ProjectServiceImpl implements ProjectService {
|
||||
throw new RuntimeException("无法读取文件内容: " + fileUrl);
|
||||
}
|
||||
|
||||
// 3. 构建输入文件信息
|
||||
List<ProjectInitRecord.InputFile> inputFiles = new ArrayList<>();
|
||||
ProjectInitRecord.InputFile inputFile = new ProjectInitRecord.InputFile();
|
||||
inputFile.setName(file.getOriginalFilename());
|
||||
inputFile.setPath(fileUrl);
|
||||
inputFile.setType(file.getContentType());
|
||||
inputFile.setSize(file.getSize());
|
||||
inputFiles.add(inputFile);
|
||||
|
||||
// 4. 生成并保存项目数据
|
||||
return generateAndSaveProjectFromContent(content, inputFiles);
|
||||
// 3. 生成并保存项目数据
|
||||
return generateAndSaveProjectFromContent(content);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("项目初始化失败: {}", e.getMessage(), e);
|
||||
@@ -234,22 +224,13 @@ public class ProjectServiceImpl implements ProjectService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ProjectInitResult generateAndSaveProjectFromContent(String content,
|
||||
List<ProjectInitRecord.InputFile> inputFiles) {
|
||||
public ProjectInitResult generateAndSaveProjectFromContent(String content) {
|
||||
log.info("开始生成并保存项目初始化数据");
|
||||
|
||||
// 1. 先创建初始化记录(状态为处理中)
|
||||
ProjectInitRecord initRecord = new ProjectInitRecord();
|
||||
initRecord.setInputFiles(inputFiles);
|
||||
initRecord.setInputText(content.length() > 5000 ? content.substring(0, 5000) + "..." : content);
|
||||
initRecord.setParseStatus("processing");
|
||||
projectInitRecordMapper.insert(initRecord);
|
||||
|
||||
ProjectInitResult result = null;
|
||||
Usage usage = null;
|
||||
ProjectInitResult result;
|
||||
|
||||
try {
|
||||
// 2. 调用AI生成项目数据
|
||||
// 1. 调用AI生成项目数据
|
||||
String userPrompt = "请根据以下项目资料,生成完整的项目初始化结构化数据:\n\n" +
|
||||
content + "\n\n" +
|
||||
"请严格按照系统提示词中的JSON格式输出,确保所有字段都包含合理的值。";
|
||||
@@ -266,38 +247,15 @@ public class ProjectServiceImpl implements ProjectService {
|
||||
// 使用 BeanOutputConverter 手动转换响应内容
|
||||
String responseContent = chatResponse.getResult().getOutput().getText();
|
||||
result = outputConverter.convert(responseContent);
|
||||
usage = chatResponse.getMetadata().getUsage();
|
||||
|
||||
// 3. 保存项目数据到数据库
|
||||
// 2. 保存项目数据到数据库
|
||||
Long projectId = saveProjectData(result);
|
||||
|
||||
// 4. 更新初始化记录为成功状态
|
||||
initRecord.setProjectId(projectId);
|
||||
initRecord.setParseStatus("completed");
|
||||
initRecord.setParseResult(result);
|
||||
initRecord.setGeneratedMilestones(result.getMilestones() != null ? result.getMilestones().size() : 0);
|
||||
initRecord.setGeneratedTasks(result.getTasks() != null ? result.getTasks().size() : 0);
|
||||
initRecord.setGeneratedMembers(result.getMembers() != null ? result.getMembers().size() : 0);
|
||||
initRecord.setGeneratedResources(result.getResources() != null ? result.getResources().size() : 0);
|
||||
if (usage != null) {
|
||||
initRecord.setTokensUsed(usage.getTotalTokens());
|
||||
}
|
||||
projectInitRecordMapper.updateById(initRecord);
|
||||
|
||||
log.info("项目初始化数据保存成功, projectId: {}", projectId);
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("项目初始化失败: {}", e.getMessage(), e);
|
||||
|
||||
// 更新初始化记录为失败状态
|
||||
initRecord.setParseStatus("failed");
|
||||
initRecord.setErrorMessage(e.getMessage());
|
||||
if (usage != null) {
|
||||
initRecord.setTokensUsed(usage.getTotalTokens());
|
||||
}
|
||||
projectInitRecordMapper.updateById(initRecord);
|
||||
|
||||
throw new RuntimeException("项目初始化失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user