Parcourir la source

通用AI审核切面类

liyafei il y a 3 mois
Parent
commit
e29d7252b0

+ 1 - 1
alien-entity/src/main/java/shop/alien/entity/store/StorePrice.java

@@ -21,7 +21,7 @@ import java.util.List;
 @JsonInclude
 @TableName("store_price")
 @ApiModel(value = "StorePrice", description = "通用价目表")
-public class StorePrice {
+public class StorePrice implements AiAuditable {
 
     @ApiModelProperty(value = "主键")
     @TableId(value = "id", type = IdType.AUTO)

+ 2 - 1
alien-entity/src/main/java/shop/alien/entity/store/dto/CuisineComboDto.java

@@ -5,12 +5,13 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import shop.alien.entity.store.AiAuditable;
 
 import java.math.BigDecimal;
 
 @Data
 @ApiModel(value = "CuisineComboDto", description = "添加美食套餐dto")
-public class CuisineComboDto {
+public class CuisineComboDto implements AiAuditable {
 
     @ApiModelProperty(value = "id,修改时必传")
     @TableField("id")

+ 0 - 7
alien-second/pom.xml

@@ -295,13 +295,6 @@
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <configuration>
                     <mainClass>shop.alien.second.AlienSecondApplication</mainClass>
-                    <layout>ZIP</layout>
-                    <includes>
-                        <include>
-                            <groupId>nothing</groupId>
-                            <artifactId>nothing</artifactId>
-                        </include>
-                    </includes>
                 </configuration>
                 <executions>
                     <execution>

+ 0 - 7
alien-store-platform/pom.xml

@@ -307,13 +307,6 @@
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <configuration>
                     <mainClass>shop.alien.storeplatform.AlienStorePlatformApplication</mainClass>
-                    <layout>ZIP</layout>
-                    <includes>
-                        <include>
-                            <groupId>nothing</groupId>
-                            <artifactId>nothing</artifactId>
-                        </include>
-                    </includes>
                 </configuration>
                 <executions>
                     <execution>

+ 58 - 35
alien-store/src/main/java/shop/alien/store/aspect/AiAuditAspect.java

@@ -9,8 +9,7 @@ import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Pointcut;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
-import shop.alien.entity.store.StorePrice;
-import shop.alien.entity.store.dto.CuisineComboDto;
+import shop.alien.entity.store.AiAuditable;
 import shop.alien.store.util.ai.AiContentModerationUtil;
 
 import java.util.ArrayList;
@@ -51,13 +50,14 @@ public class AiAuditAspect {
         String payload = JSON.toJSONString(args);
         log.info("AI审核切面拦截方法: {}, payload={}", joinPoint.getSignature().toShortString(), payload);
 
-        List<String> imageUrls = extractImageUrls(args);
+        List<AiAuditable> auditTargets = extractAuditTargets(args);
+        List<String> imageUrls = extractImageUrls(auditTargets);
 
         // AI审核:文本采用入参JSON,图片列表来自入参的 images 字符串字段
-        boolean auditPassed = performAiAudit( payload, imageUrls, args);
+        boolean auditPassed = performAiAudit(payload, imageUrls, auditTargets);
 
         // 将审核结果写入请求对象
-        applyStatus(args, auditPassed);
+        applyStatus(auditTargets, auditPassed);
 
         return joinPoint.proceed(args);
     }
@@ -65,25 +65,25 @@ public class AiAuditAspect {
     /**
      * AI审核调用:使用文本审核(图片列表暂为空)
      */
-    private boolean performAiAudit(String payload, List<String> imageUrls, Object[] args) {
+    private boolean performAiAudit(String payload, List<String> imageUrls, List<AiAuditable> auditTargets) {
         try {
             // token 目前仅预留,如后续需要可添加到header或payload
             AiContentModerationUtil.AuditResult result = aiContentModerationUtil.auditContent(payload, imageUrls);
             if (result == null) {
                 log.warn("AI审核返回为空,视为未通过");
-                applyFailureReason(args, "审核异常");
+                applyFailureReason(auditTargets, "审核异常");
                 return false;
             }
             boolean passed = result.isPassed();
             if (!passed) {
                 String reason = result.getFailureReason();
                 log.warn("AI审核不通过,原因: {}", reason);
-                applyFailureReason(args, reason);
+                applyFailureReason(auditTargets, reason);
             }
             return passed;
         } catch (Exception e) {
             log.error("AI审核调用异常", e);
-            applyFailureReason(args, "审核异常");
+            applyFailureReason(auditTargets, "审核异常");
             return false;
         }
     }
@@ -91,50 +91,73 @@ public class AiAuditAspect {
     /**
      * 将审核结果写入入参的status字段(通过=1,不通过=2)
      */
-    private void applyStatus(Object[] args, boolean passed) {
+    private void applyStatus(List<AiAuditable> auditTargets, boolean passed) {
         int status = passed ? 1 : 2;
-        for (Object arg : args) {
-            if (arg == null) {
-                continue;
-            }
-            if (arg instanceof CuisineComboDto) {
-                ((CuisineComboDto) arg).setStatus(status);
-            } else if (arg instanceof StorePrice) {
-                ((StorePrice) arg).setStatus(status);
-            }
+        for (AiAuditable target : auditTargets) {
+            target.setStatus(status);
         }
     }
 
     /**
      * 将审核失败原因写入入参
      */
-    private void applyFailureReason(Object[] args, String reason) {
+    private void applyFailureReason(List<AiAuditable> auditTargets, String reason) {
         String safeReason = reason != null ? reason : "审核未通过";
-        for (Object arg : args) {
-            if (arg == null) {
-                continue;
-            }
-            if (arg instanceof CuisineComboDto) {
-                ((CuisineComboDto) arg).setRejectionReason(safeReason);
-            } else if (arg instanceof StorePrice) {
-                ((StorePrice) arg).setRejectionReason(safeReason);
-            }
+        for (AiAuditable target : auditTargets) {
+            target.setRejectionReason(safeReason);
         }
     }
 
     /**
      * 从入参中提取图片URL列表;images字段为JSON字符串数组
      */
-    private List<String> extractImageUrls(Object[] args) {
+    private List<String> extractImageUrls(List<AiAuditable> auditTargets) {
+        if (auditTargets.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<String> urls = new ArrayList<>();
+        for (AiAuditable target : auditTargets) {
+            List<String> parsed = parseImages(target.getImages());
+            if (!parsed.isEmpty()) {
+                urls.addAll(parsed);
+            }
+        }
+        return urls;
+    }
+
+    /**
+     * 将参数中支持 AI 审核的对象提取出来,支持单个对象、集合、数组
+     */
+    private List<AiAuditable> extractAuditTargets(Object[] args) {
+        if (args == null || args.length == 0) {
+            return Collections.emptyList();
+        }
+        List<AiAuditable> targets = new ArrayList<>();
         for (Object arg : args) {
-            if (arg instanceof CuisineComboDto) {
-                return parseImages(((CuisineComboDto) arg).getImages());
+            collectAuditable(arg, targets);
+        }
+        return targets;
+    }
+
+    private void collectAuditable(Object candidate, List<AiAuditable> targets) {
+        if (candidate == null) {
+            return;
+        }
+        if (candidate instanceof AiAuditable) {
+            targets.add((AiAuditable) candidate);
+            return;
+        }
+        if (candidate instanceof Iterable<?>) {
+            for (Object item : (Iterable<?>) candidate) {
+                collectAuditable(item, targets);
             }
-            if (arg instanceof StorePrice) {
-                return parseImages(((StorePrice) arg).getImages());
+            return;
+        }
+        if (candidate instanceof Object[]) {
+            for (Object item : (Object[]) candidate) {
+                collectAuditable(item, targets);
             }
         }
-        return Collections.emptyList();
     }
 
     private List<String> parseImages(String images) {