Browse Source

聚类接口修改

master
luoweijian 2 months ago
parent
commit
186225b892
  1. 2
      src/main/java/com/project/base/domain/dto/BaseDTO.java
  2. 12
      src/main/java/com/project/base/domain/entity/BaseEntity.java
  3. 5
      src/main/java/com/project/ding/auth/DingTalkAuthenticationProvider.java
  4. 5
      src/main/java/com/project/ding/domain/enums/UserRoleEnum.java
  5. 44
      src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java
  6. 5
      src/main/java/com/project/information/controller/InformationController.java
  7. 2
      src/main/java/com/project/information/domain/dto/DraftSaveDTO.java
  8. 18
      src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java
  9. 2
      src/main/resources/application-test.yml

2
src/main/java/com/project/base/domain/dto/BaseDTO.java

@ -24,6 +24,8 @@ public class BaseDTO {
private Boolean deleted = StatusEnum.Normal.getValue(); private Boolean deleted = StatusEnum.Normal.getValue();
/** 当前登录用户是否有权限编辑(创建者或超级管理员) */
private Boolean canEdit;
public <T> T toEntity(Supplier<T> supplier) { public <T> T toEntity(Supplier<T> supplier) {
T entity = supplier.get(); T entity = supplier.get();

12
src/main/java/com/project/base/domain/entity/BaseEntity.java

@ -8,6 +8,7 @@ import com.project.base.domain.dto.BaseDTO;
import com.project.base.domain.enums.StatusEnum; import com.project.base.domain.enums.StatusEnum;
import com.project.ding.domain.entity.UserEntity; import com.project.ding.domain.entity.UserEntity;
import com.project.ding.domain.service.UserBaseService; import com.project.ding.domain.service.UserBaseService;
import com.project.ding.utils.SecurityUtils;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass; import jakarta.persistence.MappedSuperclass;
@ -67,6 +68,17 @@ public class BaseEntity implements Serializable {
} catch (Exception ignored) { } catch (Exception ignored) {
// 获取用户信息失败时不阻塞主流程 // 获取用户信息失败时不阻塞主流程
} }
// 判断当前用户是否可编辑(创建者、管理员或超级管理员)
try {
String currentUserId = SecurityUtils.getUserId();
boolean isCreator = StrUtil.equals(currentUserId, this.creatorId);
boolean isAdmin = SecurityUtils.hasRole("ROLE_ADMIN")
|| SecurityUtils.hasRole("ROLE_SUPER_ADMIN");
baseDTO.setCanEdit(isCreator || isAdmin);
} catch (Exception ignored) {
// 获取当前用户信息失败时默认不可编辑
baseDTO.setCanEdit(false);
}
} }
return dto; return dto;
} }

5
src/main/java/com/project/ding/auth/DingTalkAuthenticationProvider.java

@ -52,7 +52,7 @@ public class DingTalkAuthenticationProvider implements AuthenticationProvider {
dingUserSyncUtil.triggerSync(false); dingUserSyncUtil.triggerSync(false);
} }
// 3. 分配角色:默认考生,白名单为管理员 // 3. 分配角色:默认考生,白名单为管理员,admin_type=1 为超级管理员
List<SimpleGrantedAuthority> authorities = new ArrayList<>(); List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_CANDIDATE")); authorities.add(new SimpleGrantedAuthority("ROLE_CANDIDATE"));
LambdaQueryWrapper<AdminWhiteListEntity> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<AdminWhiteListEntity> queryWrapper = new LambdaQueryWrapper<>();
@ -60,6 +60,9 @@ public class DingTalkAuthenticationProvider implements AuthenticationProvider {
AdminWhiteListEntity existOne = whitelistMapper.selectOne(queryWrapper); AdminWhiteListEntity existOne = whitelistMapper.selectOne(queryWrapper);
if (Objects.nonNull(existOne)) { if (Objects.nonNull(existOne)) {
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
if (existOne.getAdminType() != null && existOne.getAdminType() == 1) {
authorities.add(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"));
}
} }
return new DingTalkAuthenticationToken(user, authorities); return new DingTalkAuthenticationToken(user, authorities);
} }

5
src/main/java/com/project/ding/domain/enums/UserRoleEnum.java

@ -7,7 +7,8 @@ import lombok.RequiredArgsConstructor;
@Getter @Getter
@RequiredArgsConstructor @RequiredArgsConstructor
public enum UserRoleEnum implements HasValueEnum<String> { public enum UserRoleEnum implements HasValueEnum<String> {
ROLE_CANDIDATE("考生") , ROLE_CANDIDATE("考生"),
ROLE_ADMIN("管理员"); ROLE_ADMIN("管理员"),
ROLE_SUPER_ADMIN("超级管理员");
private final String value; private final String value;
} }

44
src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java

@ -6,6 +6,7 @@ import com.project.base.config.CustomIdGenerator;
import com.project.base.domain.result.Result; import com.project.base.domain.result.Result;
import com.project.information.application.DraftReviewApplicationService; import com.project.information.application.DraftReviewApplicationService;
import com.project.information.domain.dto.DraftSaveDTO; import com.project.information.domain.dto.DraftSaveDTO;
import com.project.information.domain.dto.KnowledgePointDTO;
import com.project.information.domain.entity.InformationEntity; import com.project.information.domain.entity.InformationEntity;
import com.project.information.domain.entity.KnowledgeClusterEntity; import com.project.information.domain.entity.KnowledgeClusterEntity;
import com.project.information.domain.entity.KnowledgePointDraftEntity; import com.project.information.domain.entity.KnowledgePointDraftEntity;
@ -225,13 +226,7 @@ public class DraftReviewApplicationServiceImpl implements DraftReviewApplication
/** /**
* 触发语义聚类 * 触发语义聚类
* 当前为 mock 实现均分2个簇算法服务就绪后替换为真实调用 * 调用算法服务进行真实聚类回调结果由 saveClusterByInformationId 处理
*
* 替换方式将方法体改为
* List<KnowledgePointDTO> kpList = knowledgePoints.stream()
* .map(entity -> entity.toDTO(KnowledgePointDTO::new))
* .toList();
* algorithmApplicationService.postToClusteringByInformationId(informationId, kpList);
*/ */
private void triggerClustering(Long informationId, List<KnowledgePointEntity> knowledgePoints) { private void triggerClustering(Long informationId, List<KnowledgePointEntity> knowledgePoints) {
// 清理旧聚类数据 // 清理旧聚类数据
@ -246,35 +241,12 @@ public class DraftReviewApplicationServiceImpl implements DraftReviewApplication
return; return;
} }
// 均分为2个簇 // 转换为 DTO 并调用算法服务聚类
int mid = (int) Math.ceil(knowledgePoints.size() / 2.0); List<KnowledgePointDTO> kpList = knowledgePoints.stream()
List<List<KnowledgePointEntity>> groups = List.of( .map(entity -> entity.toDTO(KnowledgePointDTO::new))
knowledgePoints.subList(0, mid), .toList();
knowledgePoints.subList(mid, knowledgePoints.size()) algorithmApplicationService.postToClusteringByInformationId(informationId, kpList);
);
String[] topics = {"前端框架核心概念", "后端基础设施"};
for (int i = 0; i < groups.size(); i++) {
List<KnowledgePointEntity> group = groups.get(i);
if (group.isEmpty()) {
continue;
}
KnowledgeClusterEntity cluster = new KnowledgeClusterEntity();
cluster.setInformationId(informationId);
cluster.setClusterTopic(topics[i % topics.length]);
cluster.setClusterSize(group.size());
knowledgeClusterBaseService.save(cluster);
// 回写 clusterId 到知识点
List<Long> kpIds = group.stream().map(KnowledgePointEntity::getId).toList();
knowledgePointBaseService.lambdaUpdate()
.in(KnowledgePointEntity::getId, kpIds)
.set(KnowledgePointEntity::getClusterId, cluster.getId())
.update();
}
log.info(">>> [Mock聚类] 完成, informationId={}, 知识点数={}, 簇数={}", log.info(">>> [聚类] 已请求算法服务聚类, informationId={}, 知识点数={}", informationId, knowledgePoints.size());
informationId, knowledgePoints.size(), groups.stream().filter(g -> !g.isEmpty()).count());
} }
} }

5
src/main/java/com/project/information/controller/InformationController.java

@ -140,9 +140,10 @@ public class InformationController {
@PostMapping("/draft/batchSaveAndConfirm") @PostMapping("/draft/batchSaveAndConfirm")
public Result<String> batchSaveAndConfirm(Long informationId, @RequestParam("draftList") String draftListJson) throws Exception { public Result<String> batchSaveAndConfirm(Long informationId, @RequestParam("draftList") String draftListJson) throws Exception {
// Postman form-data 会对 JSON 字符串做 URL 编码,先解码 // Postman form-data 会对 JSON 字符串做 URL 编码,先解码
String decodedJson = java.net.URLDecoder.decode(draftListJson, java.nio.charset.StandardCharsets.UTF_8); // String decodedJson = java.net.URLDecoder.decode(draftListJson, java.nio.charset.StandardCharsets.UTF_8);
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
List<DraftSaveDTO> draftList = objectMapper.readValue(decodedJson, // 直接使用 draftListJson
List<DraftSaveDTO> draftList = objectMapper.readValue(draftListJson,
objectMapper.getTypeFactory().constructCollectionType(List.class, DraftSaveDTO.class)); objectMapper.getTypeFactory().constructCollectionType(List.class, DraftSaveDTO.class));
return draftReviewApplicationService.batchSaveAndConfirm(informationId, draftList); return draftReviewApplicationService.batchSaveAndConfirm(informationId, draftList);
} }

2
src/main/java/com/project/information/domain/dto/DraftSaveDTO.java

@ -1,11 +1,13 @@
package com.project.information.domain.dto; package com.project.information.domain.dto;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data; import lombok.Data;
/** /**
* 草稿批量保存DTO * 草稿批量保存DTO
*/ */
@Data @Data
@JsonIgnoreProperties(ignoreUnknown = true) // 关键:忽略未知的属性
public class DraftSaveDTO { public class DraftSaveDTO {
/** 草稿ID(新增时为null) */ /** 草稿ID(新增时为null) */

18
src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java

@ -3,8 +3,11 @@ package com.project.interaction.domain.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.information.domain.entity.InformationEntity;
import com.project.information.domain.entity.InformationFileEntity; import com.project.information.domain.entity.InformationFileEntity;
import com.project.information.domain.enums.FileParseStatusEnum; import com.project.information.domain.enums.FileParseStatusEnum;
import com.project.information.domain.enums.InformationParseStatusEnum;
import com.project.information.domain.service.InformationBaseService;
import com.project.information.domain.service.InformationFileBaseService; import com.project.information.domain.service.InformationFileBaseService;
import com.project.interaction.domain.dto.AiExtractRequestDTO; import com.project.interaction.domain.dto.AiExtractRequestDTO;
import com.project.interaction.domain.dto.DataExtractCallbackDTO; import com.project.interaction.domain.dto.DataExtractCallbackDTO;
@ -29,6 +32,9 @@ public class SaveDataExtractResultDomainServiceImpl implements SaveDataExtractRe
@Autowired @Autowired
private InformationFileBaseService informationFileBaseService; private InformationFileBaseService informationFileBaseService;
@Autowired
private InformationBaseService informationBaseService;
@Autowired @Autowired
private PostToAiExtractDomainService postToAiExtractDomainService; private PostToAiExtractDomainService postToAiExtractDomainService;
@ -73,10 +79,20 @@ public class SaveDataExtractResultDomainServiceImpl implements SaveDataExtractRe
return; return;
} }
// 3. 所有子文件均已到达终态 // 3. 所有子文件均已到达终态,判断是否全部成功
boolean allSuccess = allFiles.stream() boolean allSuccess = allFiles.stream()
.allMatch(f -> FileParseStatusEnum.Success.getValue().equals(f.getParseStatus())); .allMatch(f -> FileParseStatusEnum.Success.getValue().equals(f.getParseStatus()));
// 更新虚拟资料的解析状态(无论成功或失败都更新)
InformationEntity information = informationBaseService.getById(informationId);
if (information != null) {
information.setParseStatus(allSuccess
? InformationParseStatusEnum.Success.getValue()
: InformationParseStatusEnum.Fail.getValue());
informationBaseService.updateById(information);
log.info(">>> [数据服务回调] 虚拟资料 {} 解析状态已更新为: {}", informationId, information.getParseStatus());
}
if (!allSuccess) { if (!allSuccess) {
log.warn(">>> [数据服务回调] 虚拟资料 {} 下存在解析失败的子文件,跳过算法调用", informationId); log.warn(">>> [数据服务回调] 虚拟资料 {} 下存在解析失败的子文件,跳过算法调用", informationId);
return; return;

2
src/main/resources/application-test.yml

@ -81,7 +81,7 @@ ding:
noticeUrlPrefix: https://107pm707566hq.vicp.fun/ai-evaluator noticeUrlPrefix: https://107pm707566hq.vicp.fun/ai-evaluator
algo: algo:
clusterUrl: /semantic-cluster clusterUrl: /semantic-cluster
baseUrl: http://127.0.0.1:8002 baseUrl: http://172.16.204.50/cluster
generateQuestionUrl: /v1/generate/questions_from_cluster generateQuestionUrl: /v1/generate/questions_from_cluster
apiUrl: http://127.0.0.1:8000 apiUrl: http://127.0.0.1:8000
jwt: jwt:

Loading…
Cancel
Save