提交 145b1b92 作者: 张开石

1、生成会议纪要定时任务:转录文本和会议纪要加密保存到文件服务器

2、导出转写原文接口:添加文件解密逻辑
父级 b0bf952a
......@@ -12,6 +12,7 @@ import com.cmeeting.mapper.primary.UserIdMapper;
import com.cmeeting.pojo.MeetingInfo;
import com.cmeeting.pojo.MeetingRecordTemplate;
import com.cmeeting.service.MeetingInfoService;
import com.cmeeting.util.AESUtils;
import com.cmeeting.util.MinioUtils;
import com.cmeeting.util.R;
import com.cmeeting.vo.EmailPush;
......@@ -36,10 +37,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.format.DateTimeFormatter;
......@@ -65,6 +63,8 @@ public class MeetingInfoController {
private String permissionApplicationId;
@Value(value = "${userAdmin.file-download-path}")
private String fileDownloadPath;
@Value("${aec.key}")
public String aesKey;
@PostMapping("/updateRecordXml")
public R updateRecordXml(@RequestBody MeetingInfoVO vo) {
......@@ -132,7 +132,9 @@ public class MeetingInfoController {
public void exportMeetingRecord(@RequestBody MeetingInfoVO vo, HttpServletResponse response){
try {
MeetingInfo meetingInfo = meetingInfoService.getById(vo.getId());
String content = minioUtils.getFileText(meetingInfo.getRecordContent());
InputStream inputStream = minioUtils.getFile(meetingInfo.getRecordContent());
// 解密
String content = AESUtils.decrypt(IoUtil.read(inputStream, StandardCharsets.UTF_8), aesKey);
String fileName = String.format(meetingInfo.getSubject() + "_转写原文_%s.docx", DateUtil.today());
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
......
package com.cmeeting.job;
import cn.chatbot.meeting.DebugOutputTool;
import cn.chatbot.meeting.LLMConfig;
import cn.chatbot.meeting.LLMResult;
import cn.chatbot.meeting.MeetingProcess;
......@@ -12,17 +11,10 @@ import cn.chatbot.openai.service.LLMService;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cmeeting.ad.util.SecurityUtil;
import com.cmeeting.constant.KnowledgePlatformRouteConstant;
import com.cmeeting.constant.MeetingState;
import com.cmeeting.constant.RecordTemplateConstant;
import com.cmeeting.constant.UserAdminRouteConstant;
import com.cmeeting.dto.DocResultDto;
import com.cmeeting.dto.UserDTO;
import com.cmeeting.email.EmailSender;
import com.cmeeting.log.service.ProcessLogService;
......@@ -54,20 +46,15 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.text.MessageFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
......@@ -111,6 +98,8 @@ public class FileProcessTask {
private String applicationId;
private String fileDownloadPath;
private String permTenantId;
// AES加密秘钥
private String aesKey;
// 实际处理逻辑
......@@ -308,7 +297,7 @@ public class FileProcessTask {
processedResult = processWithClaude(recordTextBuffer.toString(),meetingDate,participantNames,template.getPrompt());
}
String minutesPath = saveResult(processedResult, recordTextBuffer.toString().getBytes(StandardCharsets.UTF_8), meetingInfo,toUserCode, template);
String minutesPath = saveResult(processedResult, recordTextBuffer.toString(), meetingInfo,toUserCode, template);
try(InputStream is = new FileInputStream(minutesPath)){
byte[] meetingMinutesBytes = IOUtils.toByteArray(is);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd");
......@@ -487,13 +476,15 @@ public class FileProcessTask {
* @param toUserCode 人员工号
* @param meetingRecordTemplate 模板信息
*/
private String saveResult(String content, byte[] recordData, MeetingInfo meetingInfo,String toUserCode,MeetingRecordTemplate meetingRecordTemplate) {
private String saveResult(String content, String recordData, MeetingInfo meetingInfo, String toUserCode, MeetingRecordTemplate meetingRecordTemplate) {
String meetingName;
//转录文件临时存储路径
// String recordContentPath = meetingId + "-recordContent-" + IdUtil.fastSimpleUUID() + ".txt";
String recordContentPath = null;
//生成的xml临时存储路径
String recordXmlPath = meetingId + "-recordXmlPath-" + IdUtil.fastSimpleUUID() + ".xml";
String uuid = IdUtil.fastSimpleUUID();
String today = DateUtil.today();
// 生成的xml临时存储路径
String recordXmlPath = String.format("%s/%s", today, meetingId + "-recordXmlPath-" + uuid + ".xml");
// 腾讯会议转录文件存储路径
String recordContentPath = String.format("%s/%s", today, meetingId + "-recordContent-" + uuid + ".txt") ;
//填充后的会议纪要名称
String meetingMinutesFileName;
//填充后的会议纪要word文件临时路径
......@@ -501,38 +492,16 @@ public class FileProcessTask {
boolean success = false;
try {
String subject = meetingInfo.getSubject();
String fileName = String.format(subject + "_转写原文_%s.txt", DateUtil.today());
MultipartFile multipartFile = new CustomMultipartFile(
"file", // 表单中的字段名
fileName, // 原始文件名
"text/plain; charset=utf-8", // MIME类型
recordData // 字节内容
);
//将转录文件存到知识向量库
String url = userAdminConfig.getUserAdminDomain() + "/robotcustom/upload";
Map<String, String> otherParams = new HashMap<>();
otherParams.put("userId", toUserCode);
otherParams.put("tenantId", permTenantId);
otherParams.put("layout", "V1");
String responseData = HttpClientKnowledgePlatformUtil.sendPostByFormDataFiles(userAdminConfig.getDocDomain() + KnowledgePlatformRouteConstant.DOC.SIMPLE_DOC_UPLOAD_URL, Arrays.asList(multipartFile), otherParams, null);
if (StringUtils.isNotBlank(responseData)) {
R result = JSON.parseObject(responseData, R.class);
List<DocResultDto> docResultDtoList = JSON.parseObject(JSONObject.toJSONString(result.getData()), new TypeReference<List<DocResultDto>>() {
});
DocResultDto docResultDto = docResultDtoList.get(0);
String previewPath = docResultDto.getPreviewPath();
recordContentPath = previewPath.replaceAll(fileDownloadPath,"");
meetingInfo.setTransDocId(docResultDto.getId());
}else{
processLogService.log(meetingId,subMeetingId,"填充会议纪要失败,上传转录文件到向量知识库失败");
throw new RuntimeException("填充会议纪要失败");
}
// 将转录文件保存到MinIO
String encryptedRecordData = AESUtils.encrypt(recordData, aesKey);
minioUtils.upload(recordContentPath, encryptedRecordData.getBytes(StandardCharsets.UTF_8));
//去除内容中除了xml内容以外其他的信息,格式化xml
String xml = extractXmlFromMarkdown(content);
// minioUtils.upload(recordContentPath,recordData);
minioUtils.upload(recordXmlPath,xml.getBytes(StandardCharsets.UTF_8));
String encryptedXml = AESUtils.encrypt(xml, aesKey);
minioUtils.upload(recordXmlPath,encryptedXml.getBytes(StandardCharsets.UTF_8));
//将xml格式的内容转换为map,用于填充模板
Map<String, Object> dataModel = convertXmlToMap(xml);
//判断会议名称关键词,如果是用户自己定义的主题,不做修改
......@@ -737,7 +706,8 @@ public class FileProcessTask {
String tencentSdkId, String tencentSecretId, String tencentSecretKey, String tencentAdminUserId,
MeetingInfoMapper meetingInfoMapper, MinioUtils minioUtils, RedisUtils redisUtils, EmailSender emailSender, MeetingRecordTemplateMapper meetingRecordTemplateMapper,
String llmApiAddr, Boolean finalRetry, ProcessLogService processLogService,List<UserDTO.TemplateAuthorizedUserDTO> authorizedUsers,Map<String,String> tidWidRelations,
UserAdminConfig userAdminConfig, String adminToken, String applicationId,String fileDownloadPath, String permTenantId) {
UserAdminConfig userAdminConfig, String adminToken, String applicationId,String fileDownloadPath, String permTenantId,
String aesKey) {
this.recordFileIdList = recordFileIdList;
this.savePath = savePath;
this.metadata = metadata;
......@@ -763,5 +733,6 @@ public class FileProcessTask {
this.applicationId = applicationId;
this.fileDownloadPath = fileDownloadPath;
this.permTenantId = permTenantId;
this.aesKey = aesKey;
}
}
\ No newline at end of file
......@@ -33,7 +33,8 @@ public class FileProcessProducer {
@Autowired
private ThreadPoolTaskExecutor fileProcessExecutor;
@Value("${aec.key}")
public String aesKey;
@Autowired
private FileProcessCallbackHandler callbackHandler;
@Value(value = "${tencent.appId}")
......@@ -110,7 +111,8 @@ public class FileProcessProducer {
adminToken,
applicationId,
fileDownloadPath,
permTenantId
permTenantId,
aesKey
);
// 提交任务到线程池
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论