提交 1a40d520 作者: duanxincheng

纪要周期流程日志;解决主持人找不到的问题;

父级 e0b7d23d
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId> <groupId>com.robot</groupId>
<artifactId>tencent_callback</artifactId> <artifactId>cmeeting </artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!--<profiles> <!--<profiles>
<profile> <profile>
...@@ -338,6 +339,24 @@ ...@@ -338,6 +339,24 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.cmeeting.TencentMeetingCallbackApplication</mainClass> <!-- 指定主类 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<version>2.7.0</version>
</plugin>
</plugins>
</build>
</project> </project>
\ No newline at end of file
Manifest-Version: 1.0
Main-Class: com.cmeeting.TencentMeetingCallbackApplication
package com.cmeeting.email; package com.cmeeting.email;
import com.cmeeting.log.service.ProcessLogService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
...@@ -8,9 +9,12 @@ import org.springframework.stereotype.Service; ...@@ -8,9 +9,12 @@ import org.springframework.stereotype.Service;
import javax.activation.DataHandler; import javax.activation.DataHandler;
import javax.activation.DataSource; import javax.activation.DataSource;
import javax.activation.FileDataSource; import javax.activation.FileDataSource;
import javax.annotation.Resource;
import javax.mail.*; import javax.mail.*;
import javax.mail.internet.*; import javax.mail.internet.*;
import java.io.File; import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
...@@ -23,6 +27,8 @@ public class EmailSender { ...@@ -23,6 +27,8 @@ public class EmailSender {
private String EMAIL_PWD; private String EMAIL_PWD;
@Value("${email.smtp-host}") @Value("${email.smtp-host}")
private String SMTP_HOST; private String SMTP_HOST;
@Resource
private ProcessLogService processLogService;
private static final Integer MAX_RETRY = 3; private static final Integer MAX_RETRY = 3;
...@@ -65,6 +71,7 @@ public class EmailSender { ...@@ -65,6 +71,7 @@ public class EmailSender {
boolean isSent = false; boolean isSent = false;
if(StringUtils.isEmpty(toEmail)){ if(StringUtils.isEmpty(toEmail)){
log.error("收件邮箱为空,推送失败"); log.error("收件邮箱为空,推送失败");
processLogService.log(meetingId,null,"收件邮箱为空,推送失败");
return false; return false;
} }
while (retryCount.intValue() < MAX_RETRY && !isSent){ while (retryCount.intValue() < MAX_RETRY && !isSent){
...@@ -103,9 +110,12 @@ public class EmailSender { ...@@ -103,9 +110,12 @@ public class EmailSender {
log.error("邮件已成功发送: meetingId->{}", meetingId); log.error("邮件已成功发送: meetingId->{}", meetingId);
isSent = true; isSent = true;
} catch (MessagingException e) { } catch (MessagingException e) {
//todo 邮件失败记录
// 异常处理
retryCount.getAndIncrement(); retryCount.getAndIncrement();
// 异常处理
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
processLogService.log(meetingId,null,"【邮件推送异常】:"+sw.toString());
if (retryCount.intValue() > MAX_RETRY) { if (retryCount.intValue() > MAX_RETRY) {
log.error("邮件发送达到最大重试次数: meetingId->{}", meetingId); log.error("邮件发送达到最大重试次数: meetingId->{}", meetingId);
throw new RuntimeException(e); throw new RuntimeException(e);
......
...@@ -17,6 +17,7 @@ import org.springframework.scheduling.annotation.Scheduled; ...@@ -17,6 +17,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
...@@ -37,6 +38,16 @@ public class CmeetingJob { ...@@ -37,6 +38,16 @@ public class CmeetingJob {
@Autowired @Autowired
private FileProcessProducer producer; private FileProcessProducer producer;
// @PostConstruct
// public void weComUserInit(){
// weComUserSync();
// }
//
// @PostConstruct
// public void tencentUserInit(){
// TencentUserSync();
// }
/** /**
* 企微人员定时同步 * 企微人员定时同步
*/ */
...@@ -122,8 +133,8 @@ public class CmeetingJob { ...@@ -122,8 +133,8 @@ public class CmeetingJob {
userIdMapper.insertUsers(userIds); userIdMapper.insertUsers(userIds);
} }
@Scheduled(fixedRate = 5 * 60 * 1000,initialDelay = 2 * 60 * 1000) // @Scheduled(fixedRate = 5 * 60 * 1000,initialDelay = 2 * 60 * 1000)
// @Scheduled(fixedRate = 5 * 60 * 1000) @Scheduled(fixedRate = 5 * 60 * 1000)
public void execute() { public void execute() {
// 定义时间格式化器 // 定义时间格式化器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
......
...@@ -36,6 +36,7 @@ import okhttp3.Response; ...@@ -36,6 +36,7 @@ import okhttp3.Response;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor; import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.*; import java.io.*;
...@@ -90,7 +91,7 @@ public class EmailPushTask { ...@@ -90,7 +91,7 @@ public class EmailPushTask {
xml = convertInputStreamToString(is); xml = convertInputStreamToString(is);
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage()); log.error(e.getMessage());
continue; throw new RuntimeException(e);
} }
//将xml格式的内容转换为map,用于填充模板 //将xml格式的内容转换为map,用于填充模板
...@@ -103,15 +104,22 @@ public class EmailPushTask { ...@@ -103,15 +104,22 @@ public class EmailPushTask {
participantsMap.put("meeting_host",meetingInfo.getHost()); participantsMap.put("meeting_host",meetingInfo.getHost());
dataModel.putAll(participantsMap); dataModel.putAll(participantsMap);
String path = Thread.currentThread().getContextClassLoader().getResource("").getPath(); String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
XWPFTemplate template = XWPFTemplate.compile(path + "template/data_net_template.docx").render(dataModel);
ClassPathResource resource = new ClassPathResource("template/data_net_template.docx");
meetingName = dataModel.get("meeting_name") != null ? String.valueOf(dataModel.get("meeting_name")) : "腾讯会议纪要"; meetingName = dataModel.get("meeting_name") != null ? String.valueOf(dataModel.get("meeting_name")) : "腾讯会议纪要";
targetFileName = meetingName + "_" + nowTime; targetFileName = meetingName + "_" + nowTime;
template.writeAndClose(new FileOutputStream(savePath + targetFileName + ".docx")); try (InputStream inputStream = resource.getInputStream()) {
byte[] recordXmlData = Files.readAllBytes(Paths.get(savePath + targetFileName + ".docx")); XWPFTemplate template = XWPFTemplate.compile(inputStream).render(dataModel);
minioUtils.upload(recordXmlPath,recordXmlData); template.writeAndClose(new FileOutputStream(path + targetFileName + ".docx"));
byte[] recordXmlData = Files.readAllBytes(Paths.get(path + targetFileName + ".docx"));
minioUtils.upload(recordXmlPath,recordXmlData);
} catch (IOException e) {
e.printStackTrace();
}
//邮件推送 //邮件推送
isSuccess = emailSender.sendEmailWithAttachment("duanxincheng@chatbot.cn",meetingName,savePath + targetFileName + ".docx",meetingId); // isSuccess = emailSender.sendEmailWithAttachment("duanxincheng@chatbot.cn",meetingName,savePath + targetFileName + ".docx",meetingId);
isSuccess = emailSender.sendEmailWithAttachment(meetingInfo.getEmail(),meetingName,savePath + targetFileName + ".docx",meetingId);
} catch (Exception e) { } catch (Exception e) {
// 异常处理 // 异常处理
int currentRetryCount = retryCount.getAndIncrement(); int currentRetryCount = retryCount.getAndIncrement();
......
...@@ -12,6 +12,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; ...@@ -12,6 +12,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cmeeting.dto.UserDTO; import com.cmeeting.dto.UserDTO;
import com.cmeeting.email.EmailSender; import com.cmeeting.email.EmailSender;
import com.cmeeting.log.service.ProcessLogService;
import com.cmeeting.mapper.primary.MeetingInfoMapper; import com.cmeeting.mapper.primary.MeetingInfoMapper;
import com.cmeeting.mapper.primary.MeetingRecordTemplateMapper; import com.cmeeting.mapper.primary.MeetingRecordTemplateMapper;
import com.cmeeting.pojo.MeetingInfo; import com.cmeeting.pojo.MeetingInfo;
...@@ -86,6 +87,7 @@ public class FileProcessTask { ...@@ -86,6 +87,7 @@ public class FileProcessTask {
private MinioUtils minioUtils; private MinioUtils minioUtils;
private EmailSender emailSender; private EmailSender emailSender;
private MeetingRecordTemplateMapper meetingRecordTemplateMapper; private MeetingRecordTemplateMapper meetingRecordTemplateMapper;
private ProcessLogService processLogService;
// 实际处理逻辑 // 实际处理逻辑
public void process() { public void process() {
...@@ -156,6 +158,7 @@ public class FileProcessTask { ...@@ -156,6 +158,7 @@ public class FileProcessTask {
} }
if(StringUtils.isEmpty(recordTextBuffer.toString().replaceAll("\\n","").trim())){ if(StringUtils.isEmpty(recordTextBuffer.toString().replaceAll("\\n","").trim())){
log.info("获取的转录文本为空,跳过纪要生成,meetingId:{},fileRecordId:{}",meetingId,recordFileIdList.toString()); log.info("获取的转录文本为空,跳过纪要生成,meetingId:{},fileRecordId:{}",meetingId,recordFileIdList.toString());
processLogService.log(meetingId,subMeetingId,"获取的转录文本为空,跳过纪要生成");
throw new RuntimeException("获取的转录文本为空,跳过纪要生成"); throw new RuntimeException("获取的转录文本为空,跳过纪要生成");
} }
// 3. 处理文件 (调用Claude API等) // 3. 处理文件 (调用Claude API等)
...@@ -166,6 +169,10 @@ public class FileProcessTask { ...@@ -166,6 +169,10 @@ public class FileProcessTask {
isSuccess = true; isSuccess = true;
} catch (Exception e) { } catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
processLogService.log(meetingId,subMeetingId,sw.toString());
// 异常处理 // 异常处理
retryCount++; retryCount++;
if (retryCount > MAX_RETRY) { if (retryCount > MAX_RETRY) {
...@@ -279,20 +286,24 @@ public class FileProcessTask { ...@@ -279,20 +286,24 @@ public class FileProcessTask {
dataModel.putAll(participantsMap); dataModel.putAll(participantsMap);
ClassPathResource resource = new ClassPathResource("template/data_net_template.docx"); ClassPathResource resource = new ClassPathResource("template/data_net_template.docx");
Properties properties = new Properties();
meetingName = dataModel.get("meeting_name") != null ? String.valueOf(dataModel.get("meeting_name")) : "腾讯会议纪要"; meetingName = dataModel.get("meeting_name") != null ? String.valueOf(dataModel.get("meeting_name")) : "腾讯会议纪要";
targetFileName = meetingName + "_" + nowTime; targetFileName = meetingName + "_" + nowTime;
XWPFTemplate template;
try (InputStream inputStream = resource.getInputStream()) { try (InputStream inputStream = resource.getInputStream()) {
XWPFTemplate template = XWPFTemplate.compile(inputStream).render(dataModel); template = XWPFTemplate.compile(inputStream).render(dataModel);
template.writeAndClose(new FileOutputStream(path + targetFileName + ".docx"));
byte[] recordXmlData = Files.readAllBytes(Paths.get(path + targetFileName + ".docx"));
minioUtils.upload(recordXmlPath,recordXmlData);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); throw new RuntimeException(e);
} }
template.writeAndClose(new FileOutputStream(path + targetFileName + ".docx"));
byte[] recordXmlData = Files.readAllBytes(Paths.get(path + targetFileName + ".docx"));
minioUtils.upload(recordXmlPath,recordXmlData);
processLogService.log(meetingId,subMeetingId,"填充会议纪要成功");
} catch (Exception e) { } catch (Exception e) {
log.error("填充会议纪要失败: {}", e.getMessage(), e); log.error("填充会议纪要失败: {}", e.getMessage(), e);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
processLogService.log(meetingId,subMeetingId,"填充会议纪要失败"+sw.toString());
throw new RuntimeException("填充会议纪要失败"); throw new RuntimeException("填充会议纪要失败");
} }
...@@ -301,11 +312,15 @@ public class FileProcessTask { ...@@ -301,11 +312,15 @@ public class FileProcessTask {
if(meetingInfo.getEmailPushAccess()){ if(meetingInfo.getEmailPushAccess()){
log.info("用户允许邮件推送,准备推送邮件至{}------",meetingInfo.getEmail()); log.info("用户允许邮件推送,准备推送邮件至{}------",meetingInfo.getEmail());
//邮件推送 //邮件推送
isPushed = emailSender.sendEmailWithAttachment("duanxincheng@chatbot.cn",meetingName,path + targetFileName + ".docx",meetingId); // isPushed = emailSender.sendEmailWithAttachment("duanxincheng@chatbot.cn",meetingName,path + targetFileName + ".docx",meetingId);
isPushed = emailSender.sendEmailWithAttachment(meetingInfo.getEmail(),meetingName,path + targetFileName + ".docx",meetingId);
if(isPushed)
processLogService.log(meetingId,subMeetingId,"用户允许邮件推送,推送邮件至"+meetingInfo.getEmail());
// emailSender.sendEmailWithAttachment("xuwentao@chatbot.cn",meetingName,path + targetFileName + ".docx",meetingId); // emailSender.sendEmailWithAttachment("xuwentao@chatbot.cn",meetingName,path + targetFileName + ".docx",meetingId);
// emailSender.sendEmailWithAttachment("jiaqi.cai@cimc.com",meetingName,path + targetFileName + ".docx",meetingId); // emailSender.sendEmailWithAttachment("jiaqi.cai@cimc.com",meetingName,path + targetFileName + ".docx",meetingId);
}else{ }else{
log.info("用户关闭了邮件推送,推送终止------"); log.info("用户关闭了邮件推送,推送终止------");
processLogService.log(meetingId,subMeetingId,"用户关闭了邮件推送,推送终止");
isPushed = Boolean.FALSE; isPushed = Boolean.FALSE;
} }
...@@ -349,7 +364,7 @@ public class FileProcessTask { ...@@ -349,7 +364,7 @@ public class FileProcessTask {
return json; return json;
} }
public static String call_llm(String apiAddr, String model, String token, List<Message> messages, int maxTokens) { private String call_llm(String apiAddr, String model, String token, List<Message> messages, int maxTokens) {
LLMService service = new LLMService(token, apiAddr); LLMService service = new LLMService(token, apiAddr);
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
try { try {
...@@ -373,6 +388,10 @@ public class FileProcessTask { ...@@ -373,6 +388,10 @@ public class FileProcessTask {
}); });
}); });
} catch (Exception e) { } catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
processLogService.log(meetingId,subMeetingId,"【大模型处理异常】:"+sw.toString());
throw new RuntimeException(e); throw new RuntimeException(e);
} }
service.shutdownExecutor(); service.shutdownExecutor();
...@@ -422,7 +441,7 @@ public class FileProcessTask { ...@@ -422,7 +441,7 @@ public class FileProcessTask {
public FileProcessTask(List<String> recordFileIdList, String meetingId, String subMeetingId, String savePath, Map<String, Object> metadata, String tencentAppId, public FileProcessTask(List<String> recordFileIdList, String meetingId, String subMeetingId, String savePath, Map<String, Object> metadata, String tencentAppId,
String tencentSdkId, String tencentSecretId, String tencentSecretKey, String tencentAdminUserId, String tencentSdkId, String tencentSecretId, String tencentSecretKey, String tencentAdminUserId,
MeetingInfoMapper meetingInfoMapper, MinioUtils minioUtils, EmailSender emailSender, MeetingRecordTemplateMapper meetingRecordTemplateMapper, MeetingInfoMapper meetingInfoMapper, MinioUtils minioUtils, EmailSender emailSender, MeetingRecordTemplateMapper meetingRecordTemplateMapper,
String llmApiAddr, Boolean finalRetry) { String llmApiAddr, Boolean finalRetry, ProcessLogService processLogService) {
this.recordFileIdList = recordFileIdList; this.recordFileIdList = recordFileIdList;
this.savePath = savePath; this.savePath = savePath;
this.metadata = metadata; this.metadata = metadata;
...@@ -439,5 +458,6 @@ public class FileProcessTask { ...@@ -439,5 +458,6 @@ public class FileProcessTask {
this.meetingRecordTemplateMapper = meetingRecordTemplateMapper; this.meetingRecordTemplateMapper = meetingRecordTemplateMapper;
this.llmApiAddr = llmApiAddr; this.llmApiAddr = llmApiAddr;
this.finalRetry = finalRetry; this.finalRetry = finalRetry;
this.processLogService = processLogService;
} }
} }
\ No newline at end of file
package com.cmeeting.log.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 纪要生成周期流程日志
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("log_process_log")
public class ProcessLog implements Serializable {
private static final long serialVersionUID = -26238487532381000L;
/**
* 主键id
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 会议ID(字符串类型)
*/
private String meetingId;
/**
* 子会议ID
*/
private String subMeetingId;
/**
* 消息
*/
private String message;
/**
* 处理时间
*/
private LocalDateTime operateTime;
}
\ No newline at end of file
package com.cmeeting.log.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.cmeeting.log.entity.ProcessLog;
public interface ProcessLogService extends IService<ProcessLog> {
boolean log(String meetingId, String subMeetingId, String message);
}
package com.cmeeting.log.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmeeting.log.entity.ProcessLog;
import com.cmeeting.mapper.primary.ProcessLogMapper;
import com.cmeeting.log.service.ProcessLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
@Slf4j
public class ProcessLogServiceImpl extends ServiceImpl<ProcessLogMapper, ProcessLog> implements ProcessLogService {
@Override
public boolean log(String meetingId, String subMeetingId, String message) {
ProcessLog processLog = ProcessLog.builder().meetingId(meetingId).subMeetingId(subMeetingId).message(message).operateTime(LocalDateTime.now()).build();
boolean save = save(processLog);
return save;
}
}
package com.cmeeting.mapper.primary;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cmeeting.log.entity.ProcessLog;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ProcessLogMapper extends BaseMapper<ProcessLog> {
}
\ No newline at end of file
...@@ -10,4 +10,6 @@ import java.util.List; ...@@ -10,4 +10,6 @@ import java.util.List;
public interface TecentMeetingMapper extends BaseMapper<TencentMeetingUser> { public interface TecentMeetingMapper extends BaseMapper<TencentMeetingUser> {
void batchInsertUsers(@Param("userList") List<TencentMeetingUser> userList); void batchInsertUsers(@Param("userList") List<TencentMeetingUser> userList);
List<TencentMeetingUser> getAlluser(); List<TencentMeetingUser> getAlluser();
String getUsernameByUserId(@Param("userId")String userId);
} }
...@@ -4,6 +4,7 @@ import com.cmeeting.dto.UserDTO; ...@@ -4,6 +4,7 @@ import com.cmeeting.dto.UserDTO;
import com.cmeeting.email.EmailSender; import com.cmeeting.email.EmailSender;
import com.cmeeting.job.EmailPushTask; import com.cmeeting.job.EmailPushTask;
import com.cmeeting.job.FileProcessTask; import com.cmeeting.job.FileProcessTask;
import com.cmeeting.log.service.ProcessLogService;
import com.cmeeting.mapper.primary.MeetingInfoMapper; import com.cmeeting.mapper.primary.MeetingInfoMapper;
import com.cmeeting.mapper.primary.MeetingRecordTemplateMapper; import com.cmeeting.mapper.primary.MeetingRecordTemplateMapper;
import com.cmeeting.pojo.UserId; import com.cmeeting.pojo.UserId;
...@@ -51,6 +52,8 @@ public class FileProcessProducer { ...@@ -51,6 +52,8 @@ public class FileProcessProducer {
private MinioUtils minioUtils; private MinioUtils minioUtils;
@Resource @Resource
private EmailSender emailSender; private EmailSender emailSender;
@Resource
private ProcessLogService processLogService;
/** /**
* 批量提交生成纪要任务 * 批量提交生成纪要任务
...@@ -79,7 +82,8 @@ public class FileProcessProducer { ...@@ -79,7 +82,8 @@ public class FileProcessProducer {
emailSender, emailSender,
meetingRecordTemplateMapper, meetingRecordTemplateMapper,
llmApiAddr, llmApiAddr,
finalRetry finalRetry,
processLogService
); );
// 提交任务到线程池 // 提交任务到线程池
......
...@@ -2,6 +2,7 @@ package com.cmeeting.service.impl; ...@@ -2,6 +2,7 @@ package com.cmeeting.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmeeting.dto.UserDTO; import com.cmeeting.dto.UserDTO;
import com.cmeeting.log.service.ProcessLogService;
import com.cmeeting.mapper.primary.AuthMapper; import com.cmeeting.mapper.primary.AuthMapper;
import com.cmeeting.mapper.primary.MeetingInfoMapper; import com.cmeeting.mapper.primary.MeetingInfoMapper;
import com.cmeeting.mapper.primary.TecentMeetingMapper; import com.cmeeting.mapper.primary.TecentMeetingMapper;
...@@ -28,6 +29,7 @@ import com.tencentcloudapi.wemeet.service.user_manager.model.V1UsersListGet200Re ...@@ -28,6 +29,7 @@ import com.tencentcloudapi.wemeet.service.user_manager.model.V1UsersListGet200Re
import com.tencentcloudapi.wemeet.service.user_manager.model.V1UsersListGet200ResponseUsersInner; import com.tencentcloudapi.wemeet.service.user_manager.model.V1UsersListGet200ResponseUsersInner;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.Headers; import okhttp3.Headers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
...@@ -35,6 +37,8 @@ import org.springframework.util.CollectionUtils; ...@@ -35,6 +37,8 @@ import org.springframework.util.CollectionUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.crypto.Mac; import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
...@@ -64,6 +68,8 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te ...@@ -64,6 +68,8 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
private UserIdMapper userIdMapper; private UserIdMapper userIdMapper;
@Resource @Resource
private RedisUtils redisUtils; private RedisUtils redisUtils;
@Resource
private ProcessLogService processLogService;
private static final String HMAC_ALGORITHM = "HmacSHA256"; private static final String HMAC_ALGORITHM = "HmacSHA256";
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
...@@ -154,7 +160,11 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te ...@@ -154,7 +160,11 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
} }
for (V1RecordsGet200ResponseRecordMeetingsInner meeting : meetings) { for (V1RecordsGet200ResponseRecordMeetingsInner meeting : meetings) {
//会议没结束,跳过 //会议没结束,跳过
if(meeting.getState() != 3) continue; if(meeting.getState() != 3){
processLogService.log(meeting.getMeetingId(),null,"会议未结束,跳过生成");
continue;
}
log.info("【会议检索】转录文件的meetingId->{},recordFileId->{}",meeting.getMeetingId(),meeting.getMeetingRecordId()); log.info("【会议检索】转录文件的meetingId->{},recordFileId->{}",meeting.getMeetingId(),meeting.getMeetingRecordId());
...@@ -190,6 +200,7 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te ...@@ -190,6 +200,7 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
.findFirst(); .findFirst();
if(!subMeeting.isPresent()){ if(!subMeeting.isPresent()){
System.out.println("周期会议"+meetingId+"未知子会议ID"); System.out.println("周期会议"+meetingId+"未知子会议ID");
processLogService.log(meeting.getMeetingId(),subMeetingId,"周期会议"+meetingId+"未知子会议ID");
continue; continue;
} }
subMeetingId = subMeeting.get().getSubMeetingId(); subMeetingId = subMeeting.get().getSubMeetingId();
...@@ -229,21 +240,37 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te ...@@ -229,21 +240,37 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
List<V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner> participants = participantsData.getParticipants(); List<V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner> participants = participantsData.getParticipants();
Optional<V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner> host = participants.stream().filter(item -> hostRoleList.contains(item.getUserRole())).findFirst(); Optional<V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner> host = participants.stream().filter(item -> hostRoleList.contains(item.getUserRole())).findFirst();
String email; String email;
String hostId;
String hostName;
//判断主持人是否存在,如果主持人未参会,是查不到主持人的
//如果主持人未参会,使用会议详情中的创建人作为主持人
if(host.isPresent()) { if(host.isPresent()) {
String tid = host.get().getUserid(); hostId = host.get().getUserid();
//判断是否有权限生成纪要 hostName = new String(Base64.getDecoder().decode(host.get().getUserName()));
boolean generateAccess = accessUserIds.stream().anyMatch(item -> item.getTid().equals(tid)); }else{
if(!generateAccess){ //未找到主持人,读取会议详情中的创建人作为主持人
log.error("【权限校验】主持人{}没有生成纪要权限,跳过生成",tid); List<V1MeetingsGet200ResponseMeetingInfoListInnerCurrentCoHostsInner> currentHosts = meetingInfo.getCurrentHosts();
if(CollectionUtils.isEmpty(currentHosts)){
log.error("未找到主持人,默认没有生成纪要权限");
processLogService.log(meeting.getMeetingId(),subMeetingId,"未找到主持人,默认没有生成纪要权限");
continue; continue;
} }
log.info("【权限校验】主持人{}允许生成纪要",tid); hostId = currentHosts.get(0).getUserid();
UserDTO userDTO = accessUserIds.stream().filter(item -> item.getTid().equals(tid)).findFirst().get(); hostName = tecentMeetingMapper.getUsernameByUserId(hostId);
email = userDTO.getEmail(); log.info("主持人会中缺席,默认会议创建人为主持人");
}else{ processLogService.log(meeting.getMeetingId(),subMeetingId,"未找到主持人,默认会议创建人为主持人");
log.error("未找到主持人,默认没有生成纪要权限"); }
//判断是否有权限生成纪要
boolean generateAccess = accessUserIds.stream().anyMatch(item -> item.getTid().equals(hostId));
if(!generateAccess){
log.error("【权限校验】主持人{}没有生成纪要权限,跳过生成",hostId);
processLogService.log(meeting.getMeetingId(),subMeetingId,"【权限校验】主持人"+hostId+"没有生成纪要权限,跳过生成");
continue; continue;
} }
log.info("【权限校验】主持人{}允许生成纪要",hostId);
processLogService.log(meeting.getMeetingId(),subMeetingId,"【权限校验】主持人"+hostId+"允许生成纪要");
UserDTO userDTO = accessUserIds.stream().filter(item -> item.getTid().equals(hostId)).findFirst().get();
email = userDTO.getEmail();
//会议基本信息保存 //会议基本信息保存
MeetingInfo meetingItem = MeetingInfo.builder().meetingId(meetingId).meetingCode(meetingInfo.getMeetingCode()) MeetingInfo meetingItem = MeetingInfo.builder().meetingId(meetingId).meetingCode(meetingInfo.getMeetingCode())
...@@ -252,8 +279,8 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te ...@@ -252,8 +279,8 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
.endTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.valueOf(meetingInfo.getEndTime())), ZoneId.systemDefault())) .endTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.valueOf(meetingInfo.getEndTime())), ZoneId.systemDefault()))
.isGenerated(Boolean.FALSE).emailPushAccess(Boolean.TRUE).isPushed(Boolean.FALSE).syncTime(LocalDateTime.now()) .isGenerated(Boolean.FALSE).emailPushAccess(Boolean.TRUE).isPushed(Boolean.FALSE).syncTime(LocalDateTime.now())
.subMeetingId(subMeetingId).generateRetry(Boolean.FALSE).pushRetry(Boolean.FALSE) .subMeetingId(subMeetingId).generateRetry(Boolean.FALSE).pushRetry(Boolean.FALSE)
.host(host.isPresent() ? new String(Base64.getDecoder().decode(host.get().getUserName())) : "未知主持人") .host(hostName)
.hostUid(host.isPresent() ? host.get().getUserid() : null) .hostUid(hostId)
.participantUsers(participants.stream() .participantUsers(participants.stream()
.map(item->new String(Base64.getDecoder().decode(item.getUserName()))).distinct().collect(Collectors.joining("、"))) .map(item->new String(Base64.getDecoder().decode(item.getUserName()))).distinct().collect(Collectors.joining("、")))
.recordFileId(recordFileIdList.stream().collect(Collectors.joining(","))) .recordFileId(recordFileIdList.stream().collect(Collectors.joining(",")))
...@@ -285,6 +312,10 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te ...@@ -285,6 +312,10 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
} }
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
processLogService.log(null,null,sw.toString());
throw new RuntimeException(e.getMessage()); throw new RuntimeException(e.getMessage());
} }
return recordFileUrlList; return recordFileUrlList;
...@@ -296,42 +327,50 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te ...@@ -296,42 +327,50 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
*/ */
@Override @Override
public List<UserDTO> getAccessUserIds() { public List<UserDTO> getAccessUserIds() {
//权限控制 try{
List<CoreModulePermissions> auths = authMapper.getAuthByTargetId(permissionApplicationId, permissionTenantId); //权限控制
//授权的部门,type为1的为人员,为0表示部门 List<CoreModulePermissions> auths = authMapper.getAuthByTargetId(permissionApplicationId, permissionTenantId);
List<CoreModulePermissions> authDepts = auths.stream().filter(item -> item.getType().equals(0)).collect(Collectors.toList()); //授权的部门,type为1的为人员,为0表示部门
List<String> deptPath = new ArrayList<>(); List<CoreModulePermissions> authDepts = auths.stream().filter(item -> item.getType().equals(0)).collect(Collectors.toList());
for (CoreModulePermissions authDept : authDepts) { List<String> deptPath = new ArrayList<>();
String deptId = authDept.getRelId(); for (CoreModulePermissions authDept : authDepts) {
String tenantId = authDept.getTenantId(); String deptId = authDept.getRelId();
getDeptPath(deptPath,deptId,tenantId); String tenantId = authDept.getTenantId();
} getDeptPath(deptPath,deptId,tenantId);
//已被授权部门下的userid }
List<String> accessUserIds = !CollectionUtils.isEmpty(deptPath) ? sysUserSyncMapper.getUsersByDept(deptPath, permissionTenantId) : new ArrayList<>(); //已被授权部门下的userid
//已被直接授权的人员追加进去 List<String> accessUserIds = !CollectionUtils.isEmpty(deptPath) ? sysUserSyncMapper.getUsersByDept(deptPath, permissionTenantId) : new ArrayList<>();
accessUserIds.addAll(auths.stream().filter(item -> item.getType().equals(1)).map(CoreModulePermissions::getRelId).collect(Collectors.toList())); //已被直接授权的人员追加进去
if(!CollectionUtils.isEmpty(accessUserIds)){ accessUserIds.addAll(auths.stream().filter(item -> item.getType().equals(1)).map(CoreModulePermissions::getRelId).collect(Collectors.toList()));
//查出人员邮箱 if(!CollectionUtils.isEmpty(accessUserIds)){
List<UserDTO> userEmailList = sysUserSyncMapper.getUserEmail(permissionTenantId); //查出人员邮箱
Map<String, String> userEmailMap = CollectionUtils.isEmpty(userEmailList) ? new HashMap<>() List<UserDTO> userEmailList = sysUserSyncMapper.getUserEmail(permissionTenantId);
: userEmailList.stream().collect(Collectors.toMap(UserDTO::getWid, UserDTO::getEmail)); Map<String, String> userEmailMap = CollectionUtils.isEmpty(userEmailList) ? new HashMap<>()
: userEmailList.stream().collect(Collectors.toMap(UserDTO::getWid, UserDTO::getEmail));
//查出企微id和腾会id的关联关系
Map<String,String> userIds = userIdMapper.selectList(null).stream().collect(Collectors.toMap(UserId::getWid,UserId::getTid)); //查出企微id和腾会id的关联关系
List<UserDTO> accessUsers = new ArrayList<>(); Map<String,String> userIds = userIdMapper.selectList(null).stream().collect(Collectors.toMap(UserId::getWid,UserId::getTid));
for (String accessUserId : accessUserIds) { List<UserDTO> accessUsers = new ArrayList<>();
if(userIds.containsKey(accessUserId)){ for (String accessUserId : accessUserIds) {
UserDTO accessUser = new UserDTO(); if(userIds.containsKey(accessUserId)){
accessUser.setWid(accessUserId); UserDTO accessUser = new UserDTO();
accessUser.setTid(userIds.get(accessUserId)); accessUser.setWid(accessUserId);
if(userEmailMap.containsKey(accessUserId)) accessUser.setTid(userIds.get(accessUserId));
accessUser.setEmail(userEmailMap.get(accessUserId)); if(userEmailMap.containsKey(accessUserId))
accessUsers.add(accessUser); accessUser.setEmail(userEmailMap.get(accessUserId));
accessUsers.add(accessUser);
}
} }
return accessUsers;
} }
return accessUsers; return new ArrayList<>();
}catch (Exception e){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
processLogService.log(null,null,sw.toString());
throw new RuntimeException(e);
} }
return new ArrayList<>();
} }
/** /**
......
Manifest-Version: 1.0
Main-Class: com.cmeeting.TencentMeetingCallbackApplication
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cmeeting.mapper.primary.ProcessLogMapper">
</mapper>
\ No newline at end of file
...@@ -21,4 +21,7 @@ ...@@ -21,4 +21,7 @@
<select id="getAlluser" resultType="com.cmeeting.pojo.TencentMeetingUser"> <select id="getAlluser" resultType="com.cmeeting.pojo.TencentMeetingUser">
SELECT * FROM user_tencentmeeting SELECT * FROM user_tencentmeeting
</select> </select>
<select id="getUsernameByUserId" resultType="java.lang.String">
SELECT user_name FROM user_tencentmeeting where user_id = #{userId}
</select>
</mapper> </mapper>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论