提交 07e5c8cf 作者: duanxincheng

模板测试效果,模板测试效果导出纪要;管理端登录白名单设置

父级 cf910187
......@@ -22,6 +22,7 @@ import com.cmeeting.util.*;
import com.cmeeting.ad.vo.ApplicationUserVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
......@@ -49,6 +50,8 @@ public class UserServiceImpl implements UserService {
private String expireTime;
@Value("${permission.tenantId}")
public String permissionTenantId;
@Value("${permission.admin-white_users}")
public String adminWhiteUsers;
@Resource
private ILdapService iLdapService;
@Resource
......@@ -253,9 +256,10 @@ public class UserServiceImpl implements UserService {
long expireDateTimestamp = vo.getExpireDate();
ZonedDateTime expireDate = Instant.ofEpochMilli(expireDateTimestamp).atZone(ZoneId.systemDefault());
ZonedDateTime now = ZonedDateTime.now();
if(expireDate.isBefore(now)){
throw new RobotBaseException("认证已过期!", 401);
}
//todo 暂时将链接设为长期有效,后续根据业务情况调整(原因是链接如果过期,普通用户没有可以跳转的登录界面,目前的管理端登录界面只能黄飞用)
// if(expireDate.isBefore(now)){
// throw new RobotBaseException("认证已过期!", 401);
// }
long expireTimeStamp = Duration.between(now, expireDate).getSeconds();
HashMap<String, String> stringStringHashMap = new HashMap<>();
SysTenant sysTenant = iTenantService.getById(permissionTenantId);
......@@ -275,12 +279,16 @@ public class UserServiceImpl implements UserService {
private R loginByAD(ApplicationUserVO.Login login) {
// AD验证
// boolean auth = iLdapService.authenticate(login.getUsername().trim(), login.getPassword().trim());
// if (auth) {
if(true){
String username = login.getUsername().trim();
boolean auth = iLdapService.authenticate(username, login.getPassword().trim());
if (auth) {
// if(true){
SysUserSync sysUserSync = sysUserSysMapper.selectOne(new LambdaQueryWrapper<SysUserSync>()
.eq(SysUserSync::getTenantId, permissionTenantId)
.eq(SysUserSync::getUserId, login.getUsername().trim()));
.eq(SysUserSync::getUserId, username));
if(StringUtils.isEmpty(adminWhiteUsers) || !Arrays.asList(adminWhiteUsers.split(",")).contains(username)){
throw new RobotBaseException("尊敬的用户 ["+sysUserSync.getName()+"],您的账户"+username+"未被授权访问此系统,请联系系统管理员。");
}
// if (code != 0) {
// throw new RuntimeException("用户系统异常!");
// }
......
package com.cmeeting.controller;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cmeeting.ad.entity.RobotSecurityUser;
import com.cmeeting.ad.util.SecurityUtil;
import com.cmeeting.dto.UserDTO;
import com.cmeeting.pojo.MeetingInfo;
import com.cmeeting.pojo.MeetingRecordTemplate;
import com.cmeeting.service.MeetingRecordTemplateService;
import com.cmeeting.service.RecordTemplatePermissionService;
import com.cmeeting.util.R;
import com.cmeeting.vo.RecordTemplateVO;
import com.deepoove.poi.XWPFTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@RestController
......@@ -39,7 +50,7 @@ public class RecordTemplateController {
recordTemplate.setCreateUserName(user.getNickName());
recordTemplate.setUpdateUserName(user.getNickName());
boolean save = recordTemplateService.save(recordTemplate);
return R.ok(save);
return R.ok(recordTemplate);
}
@PostMapping("/update")
......@@ -135,4 +146,33 @@ public class RecordTemplateController {
public R selectAuthorizedUsers() {
return R.ok(recordTemplateService.selectAuthorizedUsers());
}
/**
* 模板测试效果
* @param file 用户自主上传的转录文件
* @param meetingInstId 历史会议主键id
* @param id 模板id
* @return
*/
@PostMapping("/testGenerate")
public R testGenerate(@RequestParam(value = "file",required = false) MultipartFile file,
@RequestParam(value = "meetingInstId",required = false) Integer meetingInstId,
@RequestParam("id") Integer id) {
return R.ok(recordTemplatePermissionService.testGenerate(file,meetingInstId,id));
}
/**
* 模板测试效果导出纪要
* @param recordJson 纪要内容json
* @param meetingInstId 历史会议主键id
* @param id 模板id
* @return
*/
@PostMapping("/testMinutesExport")
public void testMinutesExport(@RequestParam(value = "recordJson") String recordJson,
@RequestParam(value = "meetingInstId",required = false) Integer meetingInstId,
@RequestParam("id") Integer id,
HttpServletResponse response) {
recordTemplatePermissionService.testMinutesExport(recordJson,meetingInstId,id,response);
}
}
......@@ -456,7 +456,7 @@ public class FileProcessTask {
"Bearer AKIAXFAXF62IWJXGLVEE.LnKInaahcMZG9zLsGMH3nTLOw3S3lK5Vcu0+ifnO",
20000);
LLMResult llmResult = MeetingProcess.processMeeting(prompt, textContent,meetingDate,participantNames, baseLLM, new ArrayList<>());
DebugOutputTool.println(llmResult.respond);
// DebugOutputTool.println(llmResult.respond);
return llmResult.respond;
}
......
......@@ -3,11 +3,17 @@ package com.cmeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.cmeeting.pojo.RecordTemplatePermission;
import com.cmeeting.vo.RecordTemplateVO;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface RecordTemplatePermissionService extends IService<RecordTemplatePermission> {
boolean auth(RecordTemplateVO.TemplatePermissionVO vo);
List<RecordTemplateVO.PermissionItem> authList(RecordTemplateVO.TemplateAuthVO vo);
String testGenerate(MultipartFile file,Integer meetingInstId,Integer templateId);
void testMinutesExport(String recordJson,Integer meetingInstId, Integer id, HttpServletResponse response);
}
package com.cmeeting.service.impl;
import cn.chatbot.meeting.DebugOutputTool;
import cn.chatbot.meeting.LLMConfig;
import cn.chatbot.meeting.LLMResult;
import cn.chatbot.meeting.MeetingProcess;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmeeting.ad.entity.RobotSecurityUser;
import com.cmeeting.ad.entity.SysDept;
import com.cmeeting.ad.entity.SysUserSync;
import com.cmeeting.ad.util.SecurityUtil;
import com.cmeeting.exception.RobotBaseException;
import com.cmeeting.mapper.primary.RecordTemplatePermissionMapper;
import com.cmeeting.mapper.secondary.SysUserSysMapper;
import com.cmeeting.pojo.MeetingInfo;
import com.cmeeting.pojo.MeetingRecordTemplate;
import com.cmeeting.pojo.RecordTemplatePermission;
import com.cmeeting.service.MeetingInfoService;
import com.cmeeting.service.MeetingRecordTemplateService;
import com.cmeeting.service.RecordTemplatePermissionService;
import com.cmeeting.util.MinioUtils;
import com.cmeeting.vo.RecordTemplateVO;
import com.deepoove.poi.XWPFTemplate;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Service
@Slf4j
public class RecordTemplatePermissionServiceImpl extends ServiceImpl<RecordTemplatePermissionMapper, RecordTemplatePermission> implements RecordTemplatePermissionService {
@Resource
private MeetingRecordTemplateService recordTemplateService;
@Resource
private MeetingInfoService meetingInfoService;
@Resource
private SysUserSysMapper sysUserSysMapper;
@Resource
private MinioUtils minioUtils;
@Value(value = "${llm.api-addr}")
private String llmApiAddr;
/**
* 授权
......@@ -107,4 +140,211 @@ public class RecordTemplatePermissionServiceImpl extends ServiceImpl<RecordTempl
}
return permissionItems;
}
/**
* 模板测试效果
* @param file 用户自主上传的转录文件
* @param meetingInstId 历史会议主键id
* @param templateId 模板id
* @return
*/
@Override
public String testGenerate(MultipartFile file, Integer meetingInstId, Integer templateId) {
if((file == null || file.isEmpty() || file.getSize() == 0) && meetingInstId == null){
throw new RobotBaseException("请提供转录文件");
}
if(templateId == null){
throw new RobotBaseException("请指定用于生成纪要的模板");
}
MeetingRecordTemplate template = recordTemplateService.getById(templateId);
if(template == null){
throw new RobotBaseException("纪要模板不存在!");
}
String prompt = template.getPrompt();
//纪要模板
String templateIndex = template.getTemplate();
String textContent;
String meetingDate = null;
String participantNames = null;
String host = null;
if(meetingInstId != null){
MeetingInfo meetingInfo = meetingInfoService.getById(meetingInstId);
if(meetingInfo == null) throw new RobotBaseException("历史会议不存在!");
String recordContent = meetingInfo.getRecordContent();
if(StringUtils.isEmpty(recordContent)) throw new RobotBaseException("历史会议的转录文件为空,请核实");
try {
textContent = minioUtils.getFileText(recordContent);
} catch (IOException e) {
throw new RobotBaseException("历史会议的转录文件内容读取失败!");
}
meetingDate = meetingInfo.getStartTime().toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
participantNames = meetingInfo.getParticipantUsers();
host = meetingInfo.getHost();
}else{
try{
byte[] bytes = file.getBytes();
textContent = new String(bytes);
}catch (Exception e){
throw new RobotBaseException("上传的转录文件内容读取失败!");
}
}
String model = "anthropic.claude-3-5-sonnet-20240620-v1:0";
LLMConfig baseLLM = new LLMConfig(model,
llmApiAddr + "/llm/sse-invoke",
"Bearer AKIAXFAXF62IWJXGLVEE.LnKInaahcMZG9zLsGMH3nTLOw3S3lK5Vcu0+ifnO",
20000);
LLMResult llmResult = MeetingProcess.processMeeting(prompt, textContent,meetingDate,participantNames, baseLLM, new ArrayList<>());
DebugOutputTool.println(llmResult.respond);
//去除内容中除了xml内容以外其他的信息,格式化xml
String xml = extractXmlFromMarkdown(llmResult.respond);
String json = convertXmlToJSON(xml);
return json;
}
@Override
public void testMinutesExport(String recordJson,Integer meetingInstId, Integer id, HttpServletResponse response) {
try {
String xml = convertJSONToXml(recordJson);
Map<String, Object> dataModel = convertXmlToMap(xml);
if(meetingInstId != null){
//追加参会人员信息
MeetingInfo meetingInfo = meetingInfoService.getById(meetingInstId);
Map<String,Object> participantsMap = new ConcurrentHashMap<>();
String meetingDate = meetingInfo.getStartTime().toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
participantsMap.put("meeting_date",meetingDate);
participantsMap.put("meeting_location","线上腾讯会议");
participantsMap.put("meeting_participants", meetingInfo.getParticipantUsers());
participantsMap.put("meeting_host",meetingInfo.getHost());
dataModel.putAll(participantsMap);
}
if(id == null){
throw new RobotBaseException("请指定用于生成纪要的模板");
}
MeetingRecordTemplate recordTemplate = recordTemplateService.getById(id);
if(recordTemplate == null){
throw new RobotBaseException("纪要模板不存在!");
}
//纪要模板
String templateIndex = recordTemplate.getTemplate();
String fileName = String.format("会议纪要效果_%s.docx", DateUtil.today());
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf8"));
XWPFTemplate template;
try (InputStream is = minioUtils.getFile(templateIndex); OutputStream os = response.getOutputStream()) {
template = XWPFTemplate.compile(is).render(dataModel);
template.write(os);
} catch (IOException e) {
throw new RuntimeException(e);
}
} catch (Exception e) {
response.reset();
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
e.printStackTrace();
}
}
private String convertXmlToJSON(String xml) {
String json;
try {
XmlMapper xmlMapper = new XmlMapper();
JsonNode rootNode = xmlMapper.readTree(xml.getBytes());
// 正确获取节点和属性的方式
List<Map> list = new ArrayList<>();
Iterator<String> iterator = rootNode.fieldNames();
while (iterator.hasNext()){
String tagName = iterator.next();
JsonNode subNode = rootNode.path(tagName);
String displayName = subNode.path("label").asText();
String content = subNode.path("").asText();
list.add(new HashMap(){{
put("key",tagName);
put("keyName",displayName);
put("value",content);
}});
}
// 构建JSON对象
ObjectMapper jsonMapper = new ObjectMapper();
json = jsonMapper.writeValueAsString(list);
} catch (IOException e) {
log.error(e.getMessage());
throw new RuntimeException(e.getMessage());
}
return json;
}
public static Map<String, Object> convertXmlToMap(String xml) {
XmlMapper xmlMapper = new XmlMapper();
ObjectMapper objectMapper = new ObjectMapper();
// 先将 XML 读取为 Map
Map<?, ?> xmlMap = null;
try {
xmlMap = xmlMapper.readValue(xml, Map.class);
} catch (JsonProcessingException e) {
throw new RobotBaseException(e.getMessage());
}
// 转换为更标准的 Map<String, Object>
Map<String,Object> map = objectMapper.convertValue(xmlMap, Map.class);
//特殊处理map格式
for (Map.Entry<String, Object> entry : map.entrySet()) {
Map<String,Object> value = (Map<String, Object>) entry.getValue();
//取出正确的value并设置
String realValue = String.valueOf(value.get("")).replaceAll("^\\n+","");
//内容段首移除换行,段末追加换行(会议名称结尾不换行
entry.setValue(realValue.endsWith("\n") || "meeting_name".equals(entry.getKey()) || "meeting_purpose".equals(entry.getKey()) ? realValue : realValue + "\n");
}
return map;
}
/**
* markdown转xml
* @param markdown
* @return
*/
private String extractXmlFromMarkdown(String markdown) {
StringBuffer sb;
try {
int start = markdown.indexOf("<");
int end = markdown.lastIndexOf(">") + 1;
sb = new StringBuffer();
sb.append("<root>");
String xml = markdown.substring(start, end).trim().replaceAll("\n\n","\n");
sb.append(xml);
sb.append("</root>");
} catch (Exception e) {
log.info("markdown转xml,markdown->{}",markdown);
throw new RuntimeException(e.getMessage());
}
return sb.toString();
}
private String convertJSONToXml(String json) {
JSONArray jsonArray = JSON.parseArray(json);
StringBuilder xmlBuilder = new StringBuilder();
xmlBuilder.append("<root>");
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObj = jsonArray.getJSONObject(i);
String key = jsonObj.getString("key");
String label = jsonObj.getString("keyName");
String value = jsonObj.getString("value");
xmlBuilder.append(String.format("<%s label=\"%s\">%s</%s>",
key, label, value, key));
}
xmlBuilder.append("</root>");
return xmlBuilder.toString();
}
}
\ No newline at end of file
......@@ -40,6 +40,7 @@ EMAIL_SMTP_HOST: smtp.office365.com
############################################################## permission
PERMISSION_APPLiCATION_ID: 1928343847335759872
PERMISSION_TENANT_ID: 1928343652791357440
PERMISSION_ADMIN_WHITE_USERS: 1928343652791357440
spring:
......@@ -151,6 +152,7 @@ jwt:
permission:
applicationId: ${PERMISSION_APPLiCATION_ID}
tenantId: ${PERMISSION_TENANT_ID}
admin-white_users: ${PERMISSION_ADMIN_WHITE_USERS}
logging:
level:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论