Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
cmeeting
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
翟斌
cmeeting
Commits
16e0183d
提交
16e0183d
authored
9月 17, 2025
作者:
洪东保
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
重新生成纪要异步处理
父级
89816a5c
显示空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
77 行增加
和
76 行删除
+77
-76
src/main/java/com/cmeeting/config/ThreadPoolConfig.java
+27
-0
src/main/java/com/cmeeting/pojo/MeetingInfo.java
+4
-0
src/main/java/com/cmeeting/service/impl/MeetingInfoServiceImpl.java
+45
-76
src/main/java/com/cmeeting/vo/MeetingInfoVO.java
+1
-0
没有找到文件。
src/main/java/com/cmeeting/config/ThreadPoolConfig.java
浏览文件 @
16e0183d
...
@@ -69,4 +69,30 @@ public class ThreadPoolConfig {
...
@@ -69,4 +69,30 @@ public class ThreadPoolConfig {
executor
.
initialize
();
executor
.
initialize
();
return
executor
;
return
executor
;
}
}
@Bean
(
"regenerateProcessExecutor"
)
public
ThreadPoolTaskExecutor
regenerateProcessExecutor
()
{
ThreadPoolTaskExecutor
executor
=
new
ThreadPoolTaskExecutor
();
// 核心线程数 (CPU密集型任务建议核心数+1)
executor
.
setCorePoolSize
(
1
);
// 固定核心线程数,避免动态获取CPU核心数
// 最大线程数
executor
.
setMaxPoolSize
(
5
);
// 队列容量
executor
.
setQueueCapacity
(
1000
);
// 线程名前缀
executor
.
setThreadNamePrefix
(
"regenerate-process-"
);
// 明确设置所有必要属性
executor
.
setAllowCoreThreadTimeOut
(
false
);
// 核心线程不允许超时
executor
.
setWaitForTasksToCompleteOnShutdown
(
true
);
// 优雅关闭
executor
.
setAwaitTerminationSeconds
(
60
);
// 等待任务完成的最大时间
// 拒绝策略
executor
.
setRejectedExecutionHandler
(
new
ThreadPoolExecutor
.
CallerRunsPolicy
());
// 初始化前打印配置检查
log
.
info
(
"Initializing RegenerateThreadPool: core={}, max={}"
,
executor
.
getCorePoolSize
(),
executor
.
getMaxPoolSize
());
executor
.
initialize
();
return
executor
;
}
}
}
\ No newline at end of file
src/main/java/com/cmeeting/pojo/MeetingInfo.java
浏览文件 @
16e0183d
...
@@ -150,6 +150,10 @@ public class MeetingInfo implements Serializable {
...
@@ -150,6 +150,10 @@ public class MeetingInfo implements Serializable {
* 转录文件知识库id
* 转录文件知识库id
*/
*/
private
String
transDocId
;
private
String
transDocId
;
/**
* 是否在重新生成
*/
private
Boolean
reprocess
=
false
;
@TableField
(
exist
=
false
)
@TableField
(
exist
=
false
)
private
String
userId
;
private
String
userId
;
...
...
src/main/java/com/cmeeting/service/impl/MeetingInfoServiceImpl.java
浏览文件 @
16e0183d
...
@@ -41,6 +41,8 @@ import com.cmeeting.service.MeetingInfoService;
...
@@ -41,6 +41,8 @@ import com.cmeeting.service.MeetingInfoService;
import
com.cmeeting.service.SysUserSyncService
;
import
com.cmeeting.service.SysUserSyncService
;
import
com.cmeeting.util.AESUtils
;
import
com.cmeeting.util.AESUtils
;
import
com.cmeeting.util.MinioUtils
;
import
com.cmeeting.util.MinioUtils
;
import
com.cmeeting.util.RedisUtils
;
import
com.cmeeting.util.TencentMeetingApiUtil
;
import
com.cmeeting.util.page.PageUtil
;
import
com.cmeeting.util.page.PageUtil
;
import
com.cmeeting.vo.MeetingInfoVO
;
import
com.cmeeting.vo.MeetingInfoVO
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
...
@@ -61,6 +63,7 @@ import okhttp3.Response;
...
@@ -61,6 +63,7 @@ import okhttp3.Response;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.util.ObjectUtils
;
...
@@ -85,16 +88,6 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
...
@@ -85,16 +88,6 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
private
MeetingInfoMapper
mapper
;
private
MeetingInfoMapper
mapper
;
@Resource
@Resource
private
MinioUtils
minioUtils
;
private
MinioUtils
minioUtils
;
@Value
(
value
=
"${tencent.appId}"
)
private
String
tencentAppId
;
@Value
(
value
=
"${tencent.sdkId}"
)
private
String
tencentSdkId
;
@Value
(
value
=
"${tencent.secretId}"
)
private
String
tencentSecretId
;
@Value
(
value
=
"${tencent.secretKey}"
)
private
String
tencentSecretKey
;
@Value
(
value
=
"${tencent.admin.userId}"
)
private
String
tencentAdminUserId
;
@Value
(
value
=
"${llm.api-addr}"
)
@Value
(
value
=
"${llm.api-addr}"
)
private
String
llmApiAddr
;
private
String
llmApiAddr
;
@Value
(
"${permission.tenantId}"
)
@Value
(
"${permission.tenantId}"
)
...
@@ -118,6 +111,11 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
...
@@ -118,6 +111,11 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
@Resource
@Resource
private
ISysUserSyncCategoryService
iSysUserSyncCategoryService
;
private
ISysUserSyncCategoryService
iSysUserSyncCategoryService
;
@Resource
(
name
=
"regenerateProcessExecutor"
)
private
ThreadPoolTaskExecutor
regenerateProcessExecutor
;
@Resource
private
RedisUtils
redisUtils
;
@Override
@Override
public
IPage
<
MeetingInfo
>
getPage
(
MeetingInfoVO
vo
)
{
public
IPage
<
MeetingInfo
>
getPage
(
MeetingInfoVO
vo
)
{
RobotSecurityUser
user
=
SecurityUtil
.
getUser
();
RobotSecurityUser
user
=
SecurityUtil
.
getUser
();
...
@@ -134,7 +132,7 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
...
@@ -134,7 +132,7 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
.
between
(
vo
.
getStartTime
()
!=
null
,
MeetingInfo:
:
getStartTime
,
vo
.
getStartTime
(),
vo
.
getEndTime
())
.
between
(
vo
.
getStartTime
()
!=
null
,
MeetingInfo:
:
getStartTime
,
vo
.
getStartTime
(),
vo
.
getEndTime
())
.
orderByDesc
(
MeetingInfo:
:
getStartTime
)
.
orderByDesc
(
MeetingInfo:
:
getStartTime
)
.
select
(
MeetingInfo:
:
getId
,
MeetingInfo:
:
getMeetingId
,
MeetingInfo:
:
getSubject
,
MeetingInfo:
:
getHost
,
MeetingInfo:
:
getHostUid
,
.
select
(
MeetingInfo:
:
getId
,
MeetingInfo:
:
getMeetingId
,
MeetingInfo:
:
getSubject
,
MeetingInfo:
:
getHost
,
MeetingInfo:
:
getHostUid
,
MeetingInfo:
:
getStartTime
,
MeetingInfo:
:
getEndTime
,
MeetingInfo:
:
getIsGenerated
,
MeetingInfo:
:
getIsPushed
);
MeetingInfo:
:
getStartTime
,
MeetingInfo:
:
getEndTime
,
MeetingInfo:
:
getIsGenerated
,
MeetingInfo:
:
getIsPushed
,
MeetingInfo:
:
getReprocess
);
Page
<
MeetingInfo
>
meetingInfoPage
=
mapper
.
selectPage
(
new
Page
<>(
vo
.
getCurrent
(),
vo
.
getSize
()),
queryWrapper
);
Page
<
MeetingInfo
>
meetingInfoPage
=
mapper
.
selectPage
(
new
Page
<>(
vo
.
getCurrent
(),
vo
.
getSize
()),
queryWrapper
);
if
(
CollUtil
.
isNotEmpty
(
meetingInfoPage
.
getRecords
()))
{
if
(
CollUtil
.
isNotEmpty
(
meetingInfoPage
.
getRecords
()))
{
List
<
MeetingInfo
>
records
=
meetingInfoPage
.
getRecords
();
List
<
MeetingInfo
>
records
=
meetingInfoPage
.
getRecords
();
...
@@ -170,14 +168,41 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
...
@@ -170,14 +168,41 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
public
boolean
regenerateXml
(
MeetingInfoVO
vo
)
{
public
boolean
regenerateXml
(
MeetingInfoVO
vo
)
{
MeetingRecordTemplate
meetingRecordTemplate
=
meetingRecordTemplateMapper
.
selectById
(
vo
.
getTemplateId
());
MeetingRecordTemplate
meetingRecordTemplate
=
meetingRecordTemplateMapper
.
selectById
(
vo
.
getTemplateId
());
if
(
meetingRecordTemplate
==
null
)
{
if
(
meetingRecordTemplate
==
null
)
{
throw
new
RobotBaseException
(
"param error! template is not exit
.
"
);
throw
new
RobotBaseException
(
"param error! template is not exit
!!
"
);
}
}
Client
client
=
new
Client
.
Builder
()
.
withAppId
(
tencentAppId
).
withSdkId
(
tencentSdkId
)
.
withSecret
(
tencentSecretId
,
tencentSecretKey
)
.
build
();
MeetingInfo
meetingInfo
=
mapper
.
selectById
(
vo
.
getId
());
MeetingInfo
meetingInfo
=
mapper
.
selectById
(
vo
.
getId
());
//已保存的会议信息
if
(
meetingInfo
==
null
)
{
throw
new
RobotBaseException
(
"meeting is not exit!!"
);
}
String
key
=
"meet_process"
+
meetingInfo
.
getMeetingId
()
+
"_"
+
(
meetingInfo
.
getSubMeetingId
()
==
null
?
""
:
meetingInfo
.
getSubMeetingId
());
if
(!
redisUtils
.
setnx
(
key
,
1
,
240
))
{
log
.
warn
(
"key already exists in redis!, key: {}"
,
key
);
return
false
;
}
regenerateProcessExecutor
.
execute
(()->{
try
{
meetingInfoMapper
.
update
(
null
,
new
LambdaUpdateWrapper
<
MeetingInfo
>()
.
eq
(
MeetingInfo:
:
getMeetingId
,
meetingInfo
.
getMeetingId
())
.
eq
(
meetingInfo
.
getSubMeetingId
()
!=
null
,
MeetingInfo:
:
getSubMeetingId
,
meetingInfo
.
getSubMeetingId
())
.
set
(
MeetingInfo:
:
getReprocess
,
true
)
);
regenerateXml
(
meetingInfo
,
meetingRecordTemplate
);
}
finally
{
meetingInfoMapper
.
update
(
null
,
new
LambdaUpdateWrapper
<
MeetingInfo
>()
.
eq
(
MeetingInfo:
:
getMeetingId
,
meetingInfo
.
getMeetingId
())
.
eq
(
meetingInfo
.
getSubMeetingId
()
!=
null
,
MeetingInfo:
:
getSubMeetingId
,
meetingInfo
.
getSubMeetingId
())
.
set
(
MeetingInfo:
:
getReprocess
,
true
)
);
redisUtils
.
del
(
key
);
}
});
return
true
;
}
public
boolean
regenerateXml
(
MeetingInfo
meetingInfo
,
MeetingRecordTemplate
meetingRecordTemplate
)
{
String
meetingId
=
meetingInfo
.
getMeetingId
();
String
meetingId
=
meetingInfo
.
getMeetingId
();
String
subMeetingId
=
meetingInfo
.
getSubMeetingId
();
String
subMeetingId
=
meetingInfo
.
getSubMeetingId
();
String
recordFileIdArray
=
meetingInfo
.
getRecordFileId
();
String
recordFileIdArray
=
meetingInfo
.
getRecordFileId
();
...
@@ -186,18 +211,8 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
...
@@ -186,18 +211,8 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
return
false
;
return
false
;
}
}
String
meetingDate
=
meetingInfo
.
getStartTime
().
toLocalDate
().
format
(
DateTimeFormatter
.
ISO_LOCAL_DATE
);
String
meetingDate
=
meetingInfo
.
getStartTime
().
toLocalDate
().
format
(
DateTimeFormatter
.
ISO_LOCAL_DATE
);
// 获取参会成员明细
// 获取参会成员明细
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetRequest
participantsRequest
=
V1MeetingsMeetingIdParticipantsGet200Response
participantsData
=
TencentMeetingApiUtil
.
ApiV1MeetingsMeetingIdParticipantsGetRequest
(
meetingId
,
subMeetingId
);
new
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetRequest
.
Builder
(
meetingId
).
subMeetingId
(
subMeetingId
).
operatorId
(
tencentAdminUserId
).
operatorIdType
(
"1"
).
build
();
AuthenticatorBuilder
<
JWTAuthenticator
>
participantsAuthenticatorBuilder
=
new
JWTAuthenticator
.
Builder
()
.
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
));
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetResponse
participantsResponse
=
client
.
meetings
().
v1MeetingsMeetingIdParticipantsGet
(
participantsRequest
,
participantsAuthenticatorBuilder
);
V1MeetingsMeetingIdParticipantsGet200Response
participantsData
=
participantsResponse
.
getData
();
List
<
V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner
>
participants
=
participantsData
.
getParticipants
();
List
<
V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner
>
participants
=
participantsData
.
getParticipants
();
String
participantNames
=
participants
.
stream
().
map
(
item
->
new
String
(
Base64
.
getDecoder
().
decode
(
item
.
getUserName
()))).
distinct
().
collect
(
Collectors
.
joining
(
"、"
));
String
participantNames
=
participants
.
stream
().
map
(
item
->
new
String
(
Base64
.
getDecoder
().
decode
(
item
.
getUserName
()))).
distinct
().
collect
(
Collectors
.
joining
(
"、"
));
meetingInfo
.
setParticipantUsers
(
participantNames
);
meetingInfo
.
setParticipantUsers
(
participantNames
);
...
@@ -207,53 +222,7 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
...
@@ -207,53 +222,7 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
List
<
String
>
recordFileIdList
=
Arrays
.
asList
(
meetingInfo
.
getRecordFileId
().
split
(
","
));
List
<
String
>
recordFileIdList
=
Arrays
.
asList
(
meetingInfo
.
getRecordFileId
().
split
(
","
));
for
(
String
recordFileId
:
recordFileIdList
)
{
for
(
String
recordFileId
:
recordFileIdList
)
{
//查询录制转写详情
//查询录制转写详情
RecordsApi
.
ApiV1AddressesRecordFileIdGetRequest
addressRequest
=
recordTextBuffer
.
append
(
TencentMeetingApiUtil
.
ApiV1AddressesRecordFileIdGetRequest
(
recordFileId
));
new
RecordsApi
.
ApiV1AddressesRecordFileIdGetRequest
.
Builder
(
recordFileId
)
.
operatorId
(
tencentAdminUserId
)
.
operatorIdType
(
"1"
)
.
build
();
RecordsApi
.
ApiV1AddressesRecordFileIdGetResponse
addressResponse
=
client
.
records
().
v1AddressesRecordFileIdGet
(
addressRequest
,
new
JWTAuthenticator
.
Builder
().
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
)));
// 处理响应
if
(
addressResponse
!=
null
&&
addressResponse
.
getData
()
!=
null
)
{
log
.
info
(
"Successfully got address for record file {}"
,
recordFileId
);
V1AddressesRecordFileIdGet200Response
addressData
=
addressResponse
.
getData
();
// 获取AI会议转录文件
List
<
V1AddressesRecordFileIdGet200ResponseAiMeetingTranscriptsInner
>
transcripts
=
addressData
.
getAiMeetingTranscripts
();
if
(
transcripts
!=
null
&&
!
transcripts
.
isEmpty
())
{
log
.
info
(
"Found {} AI meeting transcripts for record file {}"
,
transcripts
.
size
(),
recordFileId
);
// 处理每个转录文件
for
(
V1AddressesRecordFileIdGet200ResponseAiMeetingTranscriptsInner
transcript
:
transcripts
)
{
String
fileType
=
transcript
.
getFileType
();
String
downloadUrl
=
transcript
.
getDownloadAddress
();
if
(
"txt"
.
equalsIgnoreCase
(
fileType
))
{
log
.
info
(
"AI Transcript - Type: {}, URL: {}"
,
fileType
,
downloadUrl
);
// 1. 下载文件
byte
[]
fileData
=
downloadFile
(
downloadUrl
);
// 2. 将二进制文件转换为文本
String
recordTextContent
=
new
String
(
fileData
);
if
(
StringUtils
.
isNotEmpty
(
recordTextContent
.
replaceAll
(
"\\n"
,
""
).
trim
())){
recordTextBuffer
.
append
(
"\n\n"
);
recordTextBuffer
.
append
(
recordTextContent
);
}
}
}
}
else
{
log
.
info
(
"No AI meeting transcripts found for record file {}"
,
recordFileId
);
}
}
else
{
log
.
warn
(
"Empty response for record file: {}"
,
recordFileId
);
}
}
}
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
());
...
@@ -269,7 +238,7 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
...
@@ -269,7 +238,7 @@ public class MeetingInfoServiceImpl extends ServiceImpl<MeetingInfoMapper, Meeti
.
eq
(
MeetingInfo:
:
getMeetingId
,
meetingId
)
.
eq
(
MeetingInfo:
:
getMeetingId
,
meetingId
)
.
eq
(
subMeetingId
!=
null
,
MeetingInfo:
:
getSubMeetingId
,
subMeetingId
)
.
eq
(
subMeetingId
!=
null
,
MeetingInfo:
:
getSubMeetingId
,
subMeetingId
)
.
set
(
MeetingInfo:
:
getRecordXml
,
meetingInfo
.
getRecordXml
())
.
set
(
MeetingInfo:
:
getRecordXml
,
meetingInfo
.
getRecordXml
())
.
set
(
MeetingInfo:
:
getTemplateId
,
meetingRecordTemplate
.
getId
())
.
set
(
MeetingInfo:
:
getTemplateId
,
meetingRecordTemplate
.
getId
())
);
);
return
true
;
return
true
;
}
catch
(
Exception
e
){
}
catch
(
Exception
e
){
...
...
src/main/java/com/cmeeting/vo/MeetingInfoVO.java
浏览文件 @
16e0183d
...
@@ -94,6 +94,7 @@ public class MeetingInfoVO {
...
@@ -94,6 +94,7 @@ public class MeetingInfoVO {
* 邮件推送重试标识
* 邮件推送重试标识
*/
*/
private
Boolean
pushRetry
;
private
Boolean
pushRetry
;
private
Boolean
reprocess
;
/**
/**
* 同步时间
* 同步时间
*/
*/
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论