Browse Source

Merge remote-tracking branch 'origin/master'

lyx 3 months ago
parent
commit
c5aa24ef9e

+ 225 - 61
alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsServiceImpl.java

@@ -240,12 +240,8 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
                 return false;
             }
             goods = secondGoodsMapper.selectById(savedGoodsId);
-            // 执行内容审核(图片和文本)
-            if (!performContentReviews(goods, goodsDTO)) {
-                // 审核不通过,记录操作历史
-                recordGoodsOperation(goods);
-                return true; // 审核不通过时已设置状态,返回成功但标记为审核失败
-            }
+            // 审核不通过时已设置状态,返回成功但标记为审核失败
+            performContentReview(goodsDTO, goods);
 
             return true;
         } catch (Exception e) {
@@ -254,6 +250,167 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
             return false;
         }
     }
+
+    /**
+     * 执行内容审核
+     * @param goodsDTO 商品信息
+     * @param goods 商品实体
+     */
+    private void performContentReview(SecondGoodsVo goodsDTO, SecondGoods goods) throws Exception {
+        // 图片审核
+        boolean imageAuditResult = performImageReviews(goods, goodsDTO);
+        /* 添加截断,避免审核结果过多,三个顺序执行,第一个失败后直接返回,以此类推 */
+
+        // 审核失败。直接返回
+        if (!imageAuditResult) {
+            // 图片审核不通过,记录操作历史
+//            recordGoodsOperation(goods);
+            return;
+        }
+
+        // 文本审核
+        boolean textAuditResult = performTextReview(goods, goodsDTO);
+        // 审核失败。直接返回
+        if (!textAuditResult) {
+            // 文本审核不通过,记录操作历史
+//            recordGoodsOperation(goods);
+            return;
+        }
+        // 视频审核
+        List<String> taskIds = performVideoReviews(goods, goodsDTO);
+
+        // 如果成功提交了视频审核任务,设置商品状态为审核中
+        if (!taskIds.isEmpty()) {
+            goods.setGoodsStatus(SecondGoodsStatusEnum.UNDER_REVIEW.getCode()); // 审核中
+            goods.setVideoTaskId(taskIds.get(0)); // 保存第一个任务ID到商品表
+            goods.setFailedReason("");
+            updateById(goods);
+            // 审核中审核记录
+            createGoodsAudit(goods, "", Constants.AuditStatus.UNDER_REVIEW);
+            // 审核中,记录操作历史
+//            recordGoodsOperation(goods);
+            return;
+        }
+        // 审核通过后上架商品
+        approveAndListGoods(goods);
+    }
+
+    /**
+     * 创建商品审核记录
+     * @param goods 商品信息
+     */
+    private void approveAndListGoods(SecondGoods goods) {
+        // 如果所有审核都通过,设置为上架状态
+        goods.setGoodsStatus(SecondGoodsStatusEnum.LISTED.getCode()); // 上架
+        goods.setFailedReason("");
+        goods.setReleaseTime(new Date()); // 上架时间
+        updateById(goods);
+        // 插入审核记录
+        createGoodsAudit(goods, "", Constants.AuditStatus.PASSED);
+        // 发送审核成功消息
+        sendMessage(goods);
+        // 上架 记录商品操作历史
+        recordGoodsOperation(goods);
+    }
+
+    /**
+     * 执行视频审核
+     * @param goods 商品信息
+     * @param goodsDTO 商品DTO信息
+     * @return 审核结果
+     */
+    private List<String> performVideoReviews(SecondGoods goods, SecondGoodsVo goodsDTO) {
+        List<String> videoUrls = extractVideoUrls(goodsDTO.getImgUrl());
+        List<String> taskIds = new ArrayList<>();
+        // 视频审核
+        if (videoModerationEnabled) {
+            if (!videoUrls.isEmpty()) {
+                // 提交视频审核任务
+                for (String videoUrl : videoUrls) {
+                    try {
+                        String taskId = videoModerationService.submitVideoModerationTask(videoUrl);
+                        taskIds.add(taskId);
+                    } catch (Exception e) {
+                        log.error("提交视频审核任务失败,视频URL: {}", videoUrl, e);
+                        if (videoModerationBlockOnFailure) {
+                            // 视频审核提交失败,设置为审核失败状态
+                            goods.setGoodsStatus(SecondGoodsStatusEnum.REVIEW_FAILED.getCode());
+                            goods.setFailedReason("视频审核提交失败: " + e.getMessage());
+                            createGoodsAudit(goods, "视频审核提交失败", Constants.AuditStatus.FAILED);
+                            sendFailedMsg(goods);
+                        }
+                    }
+                }
+            }
+        }
+        return taskIds;
+    }
+
+    /**
+     * 执行文本审核
+     * @param goods 商品信息
+     * @param goodsDTO 商品DTO信息
+     * @return 审核结果
+     */
+    private boolean performTextReview(SecondGoods goods, SecondGoodsVo goodsDTO) throws Exception {
+        List<String> servicesList = Lists.newArrayList();
+        servicesList.add(TextReviewServiceEnum.AD_COMPLIANCE_DETECTION_PRO.getService());
+        servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
+        // 使用商品发布场景的审核服务
+        String test = goodsDTO.getDescription() + goodsDTO.getTitle() + goods.getLabel() + goods.getTopic();
+        TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(test, servicesList);
+
+        if ("high".equals(textCheckResult.getRiskLevel())) {
+            // 文本审核不通过或存在高风险
+            goods.setGoodsStatus(SecondGoodsStatusEnum.REVIEW_FAILED.getCode()); // 审核失败
+            goods.setFailedReason("文本审核不通过:" + (textCheckResult.getRiskWords() != null ? textCheckResult.getRiskWords() : "存在高风险内容"));
+            // 插入审核记录
+            createGoodsAudit(goods, textCheckResult.getRiskWords(), Constants.AuditStatus.FAILED);
+            // 发送审核失败消息
+            sendFailedMsg(goods);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 执行图片审核
+     * @param goods 商品信息
+     * @param goodsDTO 商品DTO信息
+     * @return 审核结果
+     */
+    private boolean performImageReviews(SecondGoods goods, SecondGoodsVo goodsDTO) throws Exception {
+        // 图片审核(循环处理)
+        List<String> imageUrls = goodsDTO.getImgUrl();
+        //  根据imageUrls 过滤不是图片的url
+        imageUrls = imageUrls.stream().filter(url -> url.toLowerCase().endsWith(".jpg") || url.toLowerCase().endsWith(".png") || url.toLowerCase().endsWith(".jpeg") || url.toLowerCase().endsWith(".gif")).collect(Collectors.toList());
+        // 图片审核
+        if (imageUrls != null && !imageUrls.isEmpty()) {
+            StringBuilder failReasonBuilder = new StringBuilder();
+            for (String imageUrl : imageUrls) {
+                List<String> imgServicesList = Lists.newArrayList();
+                // 内容治理检测 + AIGC图片风险检测
+                imgServicesList.add(ImageReviewServiceEnum.TONALITY_IMPROVE.getService());
+                imgServicesList.add(ImageReviewServiceEnum.AIGC_CHECK.getService());
+//                imgServicesList.add(ImageReviewServiceEnum.IMG_QUERY_SECURITY_CHECK.getService());
+                ImageModerationResultVO response = imageModerationUtil.productPublishCheck(imageUrl,imgServicesList);
+                if ("high".equals(response.getRiskLevel())) {
+                    // 图片审核不通过或存在高风险
+                    goods.setGoodsStatus(SecondGoodsStatusEnum.REVIEW_FAILED.getCode()); // 审核失败
+                    goods.setFailedReason("图片审核不通过:图片中包含" + (response.getDescriptions() != null ? response.getDescriptions() : "高风险内容"));
+                    // 插入审核记录
+                    createGoodsAudit(goods, response.getDescriptions(), Constants.AuditStatus.FAILED);
+                    // 发送审核失败消息
+                    sendFailedMsg(goods);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+
+
     /**
      * 执行内容审核(图片、文本和视频)
      * @param goods 商品信息
@@ -624,6 +781,66 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
     }
 
     /**
+     * 查询搜索结果
+     * @param page 分页参数
+     * @param secondGoodsVo 查询参数
+     * @param shieldedGoodsIds 屏蔽商品id
+     * @param userIdList 屏蔽用户id
+     * @return IPage<SecondGoodsVo> 搜索结果
+     */
+    private IPage<SecondGoodsVo> getSecondGoodsVoIPage(IPage<SecondGoodsVo> page, SecondGoodsVo secondGoodsVo, List<Integer> shieldedGoodsIds, List<Integer> userIdList) {
+        QueryWrapper<SecondGoodsVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.notIn(CollectionUtil.isNotEmpty(shieldedGoodsIds), "sg.id", shieldedGoodsIds)
+                .notIn(CollectionUtil.isNotEmpty(userIdList), "sg.user_id", userIdList)
+                .eq("sg.goods_status", SecondGoodsStatusEnum.LISTED.getCode())// 3-上架
+                .eq("sg.delete_flag", Constants.DeleteFlag.NOT_DELETED);
+        // 添加对 searchData 的模糊查询
+        if (!StringUtils.isEmpty(secondGoodsVo.getSearchData())) {
+            String searchData = "%" + secondGoodsVo.getSearchData() + "%";
+            queryWrapper.and(wrapper -> wrapper
+                .like("sg.label", searchData)
+                .or()
+                .like("sg.title", searchData)
+                .or()
+                .like("sg.description", searchData)
+                .or()
+                .like("sgc1.category_name", searchData)
+                .or()
+                .like("sgc2.category_name", searchData)
+                .or()
+                .like("sg.topic", searchData)
+            );
+        }
+        // 添加对 orderData 的排序 若不为空
+        if (!StringUtils.isEmpty(secondGoodsVo.getOrderData()) && !StringUtils.isEmpty(secondGoodsVo.getOrderType())) {
+            // 正序
+            if (secondGoodsVo.getOrderType() == 1){
+                queryWrapper.orderByAsc(secondGoodsVo.getOrderData())
+                        .orderByAsc("distance");
+            }
+            // 倒序
+            if (secondGoodsVo.getOrderType() == 2){
+                queryWrapper.orderByDesc(secondGoodsVo.getOrderData())
+                        .orderByAsc("distance");
+            }
+        }else {
+            queryWrapper.orderByAsc("distance");
+        }
+
+        // 添加对 releaseTime 的查询
+        if (secondGoodsVo.getReleaseTime() != null) {
+            queryWrapper.eq("sg.release_time", secondGoodsVo.getReleaseTime());
+        }
+
+        // 返回分页结果
+        IPage<SecondGoodsVo> searchGoodsList = secondGoodsMapper.searchGoodsList(page, secondGoodsVo.getCurrentLatitude(), secondGoodsVo.getCurrentLongitude() ,queryWrapper);
+        searchGoodsList.getRecords().forEach(secondGoods -> {
+            secondGoods.setPosition(secondGoods.getSearchData());
+        });
+        return searchGoodsList;
+    }
+
+    /**
      * 批量设置收藏状态
      * @param searchGoodsList 搜索结果列表
      * @param userId 用户ID(登录用户)
@@ -915,6 +1132,8 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
                 
                 // 发送审核成功消息
                 sendMessage(goods);
+                // 审核成功,记录操作历史
+                recordGoodsOperation(goods);
             } else {
                 // 审核不通过
                 goods.setGoodsStatus(SecondGoodsStatusEnum.REVIEW_FAILED.getCode());
@@ -1001,61 +1220,6 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
     }
 
     /**
-     * 查询搜索结果
-     * @param page 分页参数
-     * @param secondGoodsVo 查询参数
-     * @param shieldedGoodsIds 屏蔽商品id
-     * @param userIdList 屏蔽用户id
-     * @return IPage<SecondGoodsVo> 搜索结果
-     */
-    private IPage<SecondGoodsVo> getSecondGoodsVoIPage(IPage<SecondGoodsVo> page, SecondGoodsVo secondGoodsVo, List<Integer> shieldedGoodsIds, List<Integer> userIdList) {
-        QueryWrapper<SecondGoodsVo> queryWrapper = new QueryWrapper<>();
-        queryWrapper.notIn(CollectionUtil.isNotEmpty(shieldedGoodsIds), "sg.id", shieldedGoodsIds)
-                .notIn(CollectionUtil.isNotEmpty(userIdList), "sg.user_id", userIdList)
-                .eq("sg.goods_status", SecondGoodsStatusEnum.LISTED.getCode())// 3-上架
-                .eq("sg.delete_flag", Constants.DeleteFlag.NOT_DELETED);
-        // 添加对 searchData 的模糊查询
-        if (!StringUtils.isEmpty(secondGoodsVo.getSearchData())) {
-            String searchData = "%" + secondGoodsVo.getSearchData() + "%";
-            queryWrapper.and(wrapper -> wrapper
-                .like("sg.label", searchData)
-                .or()
-                .like("sg.title", searchData)
-                .or()
-                .like("sg.description", searchData)
-                .or()
-                .like("sgc1.category_name", searchData)
-                .or()
-                .like("sgc2.category_name", searchData)
-                .or()
-                .like("sg.topic", searchData)
-            );
-        }
-        // 添加对 orderData 的排序 若不为空
-        if (!StringUtils.isEmpty(secondGoodsVo.getOrderData()) && !StringUtils.isEmpty(secondGoodsVo.getOrderType())) {
-            // 正序
-            if (secondGoodsVo.getOrderType() == 1){
-                queryWrapper.orderByAsc(secondGoodsVo.getOrderData())
-                        .orderByAsc("distance");
-            }
-            // 倒序
-            if (secondGoodsVo.getOrderType() == 2){
-                queryWrapper.orderByDesc(secondGoodsVo.getOrderData())
-                        .orderByAsc("distance");
-            }
-        }else {
-            queryWrapper.orderByAsc("distance");
-        }
-
-        // 返回分页结果
-        IPage<SecondGoodsVo> searchGoodsList = secondGoodsMapper.searchGoodsList(page, secondGoodsVo.getCurrentLatitude(), secondGoodsVo.getCurrentLongitude() ,queryWrapper);
-        searchGoodsList.getRecords().forEach(secondGoods -> {
-            secondGoods.setPosition(secondGoods.getSearchData());
-        });
-        return searchGoodsList;
-    }
-
-    /**
      * 批量设置用户信息(用于SecondGoodsVo列表)
      * @param searchGoodsList 搜索结果
      */

+ 6 - 0
alien-util/src/main/java/shop/alien/util/common/Constants.java

@@ -53,6 +53,12 @@ public class Constants {
          * 审核通过
          */
         public static final Integer PASSED = 1;
+
+        /**
+         * 审核中
+         */
+        public static final Integer UNDER_REVIEW = 0;
+
     }
     
     /**