feat(project): 实现AI项目初始化及数据保存功能

- 新增ProjectController,支持文件上传生成项目初始化预览数据
- 添加接口确认并保存用户确认后的项目初始化数据到数据库
- ProjectService接口新增预览数据生成与保存方法定义
- 实现ProjectServiceImpl,支持AI解析项目文档生成结构化数据
- 集成文件上传至OSS并读取内容进行项目数据生成
- 实现数据库保存逻辑,涵盖项目基本信息、里程碑、任务及依赖
- 完成项目成员、资源、风险和时间节点的转换及持久化
- 完善日志与异常处理,确保流程可跟踪及失败提示
- 定义并使用系统与用户提示词模板用于AI交互生成项目数据
This commit is contained in:
2026-03-27 12:01:49 +08:00
parent 5e698fbb8c
commit a5e62e6885
3 changed files with 57 additions and 50 deletions

View File

@@ -24,26 +24,50 @@ public class ProjectController {
private final OssService ossService;
/**
* 上传文件并生成项目初始化数据
* 上传文件并生成项目初始化预览数据(不入库)
*
* @param file 项目资料文件
* @return 项目初始化结构化数据
* @return 项目初始化结构化数据预览
*/
@PostMapping("/from-file")
public BaseResponse<ProjectInitResult> generateFromFile(@RequestParam("file") MultipartFile file) {
log.info("收到项目初始化请求(文件上传), 文件名: {}", file.getOriginalFilename());
@PostMapping("/preview")
public BaseResponse<ProjectInitResult> generatePreview(@RequestParam("file") MultipartFile file) {
log.info("收到项目初始化预览请求, 文件名: {}", file.getOriginalFilename());
if (file.isEmpty()) {
return ResultUtils.error("上传文件不能为空");
}
try {
// 上传文件生成项目初始化数据并保存到数据库
ProjectInitResult result = projectService.generateAndSaveProject(file);
return ResultUtils.success("项目初始化成功", result);
// 上传文件生成项目初始化预览数据(不入库)
ProjectInitResult result = projectService.generateProjectPreview(file);
return ResultUtils.success("项目预览数据生成成功", result);
} catch (Exception e) {
log.error("项目初始化失败: {}", e.getMessage(), e);
return ResultUtils.error("项目初始化失败: " + e.getMessage());
log.error("项目预览生成失败: {}", e.getMessage(), e);
return ResultUtils.error("项目预览生成失败: " + e.getMessage());
}
}
/**
* 确认并保存项目初始化数据
*
* @param result 用户确认后的项目初始化数据
* @return 保存后的项目初始化数据
*/
@PostMapping("/confirm")
public BaseResponse<ProjectInitResult> confirmAndSave(@RequestBody ProjectInitResult result) {
log.info("收到项目初始化确认请求");
if (result == null || result.getProject() == null) {
return ResultUtils.error("项目数据不能为空");
}
try {
// 保存项目数据到数据库
ProjectInitResult savedResult = projectService.saveProjectData(result);
return ResultUtils.success("项目创建成功", savedResult);
} catch (Exception e) {
log.error("项目保存失败: {}", e.getMessage(), e);
return ResultUtils.error("项目保存失败: " + e.getMessage());
}
}

View File

@@ -27,18 +27,18 @@ public interface ProjectService {
ProjectInitResult generateProjectFromFile(String fileUrl, String fileType);
/**
* 上传文件并生成项目初始化数据,同时保存到数据库
* 上传文件并生成项目初始化预览数据(不入库)
*
* @param file 项目资料文件
* @return 项目初始化结果
* @return 项目初始化预览结果
*/
ProjectInitResult generateAndSaveProject(MultipartFile file);
ProjectInitResult generateProjectPreview(MultipartFile file);
/**
* 根据项目资料内容生成并保存项目初始化数据
* 保存项目初始化数据到数据库
*
* @param content 项目资料文本内容
* @return 项目初始化结果
* @param result 用户确认后的项目初始化数据
* @return 保存后的项目初始化结果包含生成的ID等信息
*/
ProjectInitResult generateAndSaveProjectFromContent(String content);
ProjectInitResult saveProjectData(ProjectInitResult result);
}

View File

@@ -200,9 +200,8 @@ public class ProjectServiceImpl implements ProjectService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public ProjectInitResult generateAndSaveProject(MultipartFile file) {
log.info("开始上传文件并生成项目初始化数据, 文件名: {}", file.getOriginalFilename());
public ProjectInitResult generateProjectPreview(MultipartFile file) {
log.info("开始上传文件并生成项目初始化预览数据, 文件名: {}", file.getOriginalFilename());
try {
// 1. 上传文件到OSS
@@ -215,50 +214,34 @@ public class ProjectServiceImpl implements ProjectService {
throw new RuntimeException("无法读取文件内容: " + fileUrl);
}
// 3. 生成并保存项目数据
return generateAndSaveProjectFromContent(content);
// 3. 调用AI生成项目预览数据不入库
return generateProjectFromContent(content);
} catch (Exception e) {
log.error("项目初始化失败: {}", e.getMessage(), e);
throw new RuntimeException("项目初始化失败: " + e.getMessage(), e);
log.error("项目预览生成失败: {}", e.getMessage(), e);
throw new RuntimeException("项目预览生成失败: " + e.getMessage(), e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public ProjectInitResult generateAndSaveProjectFromContent(String content) {
log.info("开始生成并保存项目初始化数据");
public ProjectInitResult saveProjectData(ProjectInitResult result) {
log.info("开始保存项目初始化数据");
ProjectInitResult result;
if (result == null || result.getProject() == null) {
throw new RuntimeException("项目数据为空");
}
try {
// 1. 调用AI生成项目数据
String userPrompt = "请根据以下项目资料,生成完整的项目初始化结构化数据:\n\n" +
content + "\n\n" +
"请严格按照系统提示词中的JSON格式输出确保所有字段都包含合理的值。";
// 创建 BeanOutputConverter 用于转换响应
BeanOutputConverter<ProjectInitResult> outputConverter = new BeanOutputConverter<>(ProjectInitResult.class);
var chatResponse = chatClient.prompt()
.system(PROJECT_INIT_SYSTEM_PROMPT)
.user(userPrompt)
.call()
.chatResponse();
// 使用 BeanOutputConverter 手动转换响应内容
String responseContent = chatResponse.getResult().getOutput().getText();
result = outputConverter.convert(responseContent);
// 2. 保存项目数据到数据库
Long projectId = saveProjectData(result);
// 保存项目数据到数据库
Long projectId = saveProjectDataToDb(result);
log.info("项目初始化数据保存成功, projectId: {}", projectId);
return result;
} catch (Exception e) {
log.error("项目初始化失败: {}", e.getMessage(), e);
throw new RuntimeException("项目初始化失败: " + e.getMessage(), e);
log.error("项目保存失败: {}", e.getMessage(), e);
throw new RuntimeException("项目保存失败: " + e.getMessage(), e);
}
}
@@ -268,7 +251,7 @@ public class ProjectServiceImpl implements ProjectService {
* @param result AI生成的项目初始化结果
* @return 项目ID
*/
private Long saveProjectData(ProjectInitResult result) {
private Long saveProjectDataToDb(ProjectInitResult result) {
if (result == null || result.getProject() == null) {
throw new RuntimeException("项目数据为空");
}