|
|
@@ -0,0 +1,171 @@
|
|
|
+package shop.alien.store.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import shop.alien.entity.store.StoreStaffConfig;
|
|
|
+import shop.alien.mapper.StoreStaffConfigMapper;
|
|
|
+import shop.alien.store.util.ai.AiContentModerationUtil;
|
|
|
+import shop.alien.store.util.ai.AiVideoModerationUtil;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 员工审核异步服务
|
|
|
+ * 用于异步处理员工内容的AI审核
|
|
|
+ *
|
|
|
+ * @author assistant
|
|
|
+ * @since 2025-01-07
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class StoreStaffAuditAsyncService {
|
|
|
+
|
|
|
+ private final StoreStaffConfigMapper storeStaffConfigMapper;
|
|
|
+ private final AiContentModerationUtil aiContentModerationUtil;
|
|
|
+ private final AiVideoModerationUtil aiVideoModerationUtil;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断URL是否为视频
|
|
|
+ *
|
|
|
+ * @param url URL地址
|
|
|
+ * @return 是否为视频
|
|
|
+ */
|
|
|
+ private boolean isVideoUrl(String url) {
|
|
|
+ if (url == null || url.isEmpty()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ String lowerUrl = url.toLowerCase();
|
|
|
+ return lowerUrl.endsWith(".mp4") ||
|
|
|
+ lowerUrl.endsWith(".avi") ||
|
|
|
+ lowerUrl.endsWith(".flv") ||
|
|
|
+ lowerUrl.endsWith(".mkv") ||
|
|
|
+ lowerUrl.endsWith(".rmvb") ||
|
|
|
+ lowerUrl.endsWith(".wmv") ||
|
|
|
+ lowerUrl.endsWith(".3gp") ||
|
|
|
+ lowerUrl.endsWith(".mov");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 异步审核员工内容
|
|
|
+ *
|
|
|
+ * @param staffId 员工ID
|
|
|
+ * @param storeStaffConfig 员工配置信息
|
|
|
+ */
|
|
|
+ @Async
|
|
|
+ public void auditStaffContentAsync(Integer staffId, StoreStaffConfig storeStaffConfig) {
|
|
|
+ try {
|
|
|
+ log.info("开始异步审核员工内容,staffId={}", staffId);
|
|
|
+
|
|
|
+ // 将状态置为"审核中"(0),清空拒绝原因
|
|
|
+ StoreStaffConfig auditingUpdate = new StoreStaffConfig();
|
|
|
+ auditingUpdate.setId(staffId);
|
|
|
+ auditingUpdate.setStatus("0");
|
|
|
+ auditingUpdate.setRejectionReason(null);
|
|
|
+ storeStaffConfigMapper.updateById(auditingUpdate);
|
|
|
+
|
|
|
+ // 组装 AI 审核文本和图片
|
|
|
+ StringBuilder textContent = new StringBuilder();
|
|
|
+ if (StringUtils.isNotEmpty(storeStaffConfig.getName())) {
|
|
|
+ textContent.append(storeStaffConfig.getName()).append(" ");
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(storeStaffConfig.getStaffPosition())) {
|
|
|
+ textContent.append(storeStaffConfig.getStaffPosition()).append(" ");
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(storeStaffConfig.getPersonalIntroduction())) {
|
|
|
+ textContent.append(storeStaffConfig.getPersonalIntroduction());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(storeStaffConfig.getProficientProjects())) {
|
|
|
+ textContent.append(storeStaffConfig.getProficientProjects());
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> imageUrls = new ArrayList<>();
|
|
|
+ List<String> videoUrls = new ArrayList<>();
|
|
|
+
|
|
|
+ if (StringUtils.isNotEmpty(storeStaffConfig.getStaffImage())) {
|
|
|
+ imageUrls.add(storeStaffConfig.getStaffImage());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(storeStaffConfig.getBackgroundUrl())) {
|
|
|
+ String[] urls = storeStaffConfig.getBackgroundUrl().split(",");
|
|
|
+ for (String url : urls) {
|
|
|
+ if (StringUtils.isNotEmpty(url.trim())) {
|
|
|
+ String trimmedUrl = url.trim();
|
|
|
+ // 判断是视频还是图片
|
|
|
+ if (isVideoUrl(trimmedUrl)) {
|
|
|
+ videoUrls.add(trimmedUrl);
|
|
|
+ } else {
|
|
|
+ imageUrls.add(trimmedUrl);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 审核文本和图片
|
|
|
+ AiContentModerationUtil.AuditResult textImageAuditResult = aiContentModerationUtil.auditContent(
|
|
|
+ textContent.toString().trim(), imageUrls
|
|
|
+ );
|
|
|
+
|
|
|
+ // 2. 审核视频(如果有)
|
|
|
+ AiVideoModerationUtil.VideoAuditResult videoAuditResult = null;
|
|
|
+ if (!videoUrls.isEmpty()) {
|
|
|
+ log.info("开始审核视频,视频数量:{}", videoUrls.size());
|
|
|
+ videoAuditResult = aiVideoModerationUtil.auditVideos(videoUrls);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 综合审核结果:文本图片审核和视频审核都必须通过
|
|
|
+ boolean allPassed = (textImageAuditResult != null && textImageAuditResult.isPassed()) &&
|
|
|
+ (videoAuditResult == null || videoAuditResult.isPassed());
|
|
|
+
|
|
|
+ // 根据 AI 审核结果更新状态
|
|
|
+ // 审核通过:状态保持为"1"(审核通过)
|
|
|
+ // 审核失败:状态设置为"2"(审核拒绝)
|
|
|
+ StoreStaffConfig auditUpdate = new StoreStaffConfig();
|
|
|
+ auditUpdate.setId(staffId);
|
|
|
+ if (allPassed) {
|
|
|
+ // AI审核通过,状态保持为"审核中"(1)
|
|
|
+ auditUpdate.setStatus("1");
|
|
|
+ auditUpdate.setRejectionReason(null);
|
|
|
+ log.info("人员AI审核通过,状态设置为审核通过:staffId={}", staffId);
|
|
|
+ } else {
|
|
|
+ // AI审核失败,状态设置为"审核拒绝"(2)
|
|
|
+ // 收集所有失败原因
|
|
|
+ List<String> failureReasons = new ArrayList<>();
|
|
|
+ if (textImageAuditResult != null && !textImageAuditResult.isPassed()) {
|
|
|
+ if (StringUtils.isNotEmpty(textImageAuditResult.getFailureReason())) {
|
|
|
+ failureReasons.add("图文审核:" + textImageAuditResult.getFailureReason());
|
|
|
+ } else {
|
|
|
+ failureReasons.add("图文审核未通过");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (videoAuditResult != null && !videoAuditResult.isPassed()) {
|
|
|
+ // 业务要求:视频审核失败统一记录"视频内容违规"
|
|
|
+ failureReasons.add("视频内容违规");
|
|
|
+ }
|
|
|
+
|
|
|
+ String reason = failureReasons.isEmpty() ? "审核未通过" : String.join("; ", failureReasons);
|
|
|
+ log.warn("人员AI审核失败,状态设置为审核拒绝:staffId={}, reason={}", staffId, reason);
|
|
|
+ auditUpdate.setStatus("2");
|
|
|
+ auditUpdate.setRejectionReason(reason);
|
|
|
+ }
|
|
|
+ storeStaffConfigMapper.updateById(auditUpdate);
|
|
|
+
|
|
|
+ log.info("异步审核员工内容完成,staffId={}", staffId);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("异步审核员工内容异常,staffId={},异常信息:{}", staffId, e.getMessage(), e);
|
|
|
+ // 审核失败时,设置为审核拒绝状态
|
|
|
+ try {
|
|
|
+ StoreStaffConfig auditUpdate = new StoreStaffConfig();
|
|
|
+ auditUpdate.setId(staffId);
|
|
|
+ auditUpdate.setStatus("2");
|
|
|
+ auditUpdate.setRejectionReason("审核系统异常,请稍后重试");
|
|
|
+ storeStaffConfigMapper.updateById(auditUpdate);
|
|
|
+ } catch (Exception updateException) {
|
|
|
+ log.error("更新审核失败状态异常,staffId={},异常信息:{}", staffId, updateException.getMessage(), updateException);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|