Quellcode durchsuchen

feat(store): 实现AI内容审核及结果获取功能

- 移除冗余的Jackson依赖和Alipay工具类引用
- 修改文件后缀判断逻辑,去除前导点号以适配实际场景
- 使用FastJSON2替换ObjectMapper处理HTTP响应内容
- 新增定时任务getCheckTask用于获取AI审核违规结果
- 在LifeUserDynamics实体中增加aiTaskId和reason字段
- 控制器新增testAI与testAIGet方法用于调试AI接口
- 完善AI审核流程,支持图文视频多媒体内容提交
- 增加审核失败原因记录和状态更新机制
Lhaibo vor 2 Wochen
Ursprung
Commit
94b17c3fc2

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

@@ -136,5 +136,9 @@ public class LifeUserDynamics {
 
     @ApiModelProperty(value = "AI审核结果查询id")
     @TableField("ai_task_id")
-    private Integer aiTaskId;
+    private String aiTaskId;
+
+    @ApiModelProperty(value = "审核失败原因")
+    @TableField("reason")
+    private String reason;
 }

+ 105 - 23
alien-job/src/main/java/shop/alien/job/store/AiTagJob.java

@@ -3,9 +3,6 @@ package shop.alien.job.store;
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.xxl.job.core.context.XxlJobHelper;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.RequiredArgsConstructor;
@@ -25,8 +22,6 @@ import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 
-import static com.alipay.api.internal.util.AlipayUtils.getFileSuffix;
-
 /**
  * 调用AI标签数据服务类
  *
@@ -38,8 +33,6 @@ import static com.alipay.api.internal.util.AlipayUtils.getFileSuffix;
 @RequiredArgsConstructor
 public class AiTagJob {
 
-    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
-
     private final RestTemplate restTemplate;
 
     private final TagsMainMapper tagsMainMapper;
@@ -584,11 +577,11 @@ public class AiTagJob {
 
         // 常见图片后缀(可按需添加,如 .heic、.svg 等)
         HashSet<String> IMAGE_SUFFIXES = new HashSet<>(Arrays.asList(
-                ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".heic", ".svg", ".tiff"
+                "jpg", "jpeg", "png", "gif", "bmp", "webp", "heic", "svg", "tiff"
         ));
         // 常见视频后缀(可按需添加,如 .avi、.flv 等)
         HashSet<String> VIDEO_SUFFIXES = new HashSet<>(Arrays.asList(
-                ".mp4", ".mov", ".mkv", ".avi", ".flv", ".wmv", ".mpeg", ".mpg", ".webm"
+                "mp4", "mov", "mkv", "avi", "flv", "wmv", "mpeg", "mpg", "webm"
         ));
 
         for (LifeUserDynamics lifeUserDynamic : lifeUserDynamics) {
@@ -656,21 +649,26 @@ public class AiTagJob {
                                 if (response.getStatusCodeValue() != 200) {
                                     log.error("AI内容审核接口调用失败 http状态:" + response.getStatusCode());
                                 }
-                                JsonNode responseNode = OBJECT_MAPPER.readTree(response.getBody());
-                                int code = responseNode.has("code") ? responseNode.get("code").asInt() : 0;
-                                if (code != 200) {
-                                    throw new RuntimeException("AI接口调用失败" + code);
+                                JSONObject responseNode = JSONObject.parseObject(response.getBody());
+                                if (responseNode == null) {
+                                    log.error("AI接口调用失败,响应内容为空");
                                 }
-                                JsonNode dataNode = responseNode.get("data");
-
-                                if (dataNode.has("is_compliant")) {
-                                    LifeUserDynamics dynamics = new LifeUserDynamics();
-                                    dynamics.setId(lifeUserDynamic.getId());
-                                    dynamics.setCheckFlag(1);
-                                    lifeUserDynamicsMapper.updateById(dynamics);
+                                Integer code = null;
+                                if (responseNode != null) {
+                                    code = responseNode.getInteger("code");
+                                    if(code==200) {
+                                        JSONObject dataNode = JSONObject.from(responseNode.get("data"));
+                                        LifeUserDynamics dynamics = new LifeUserDynamics();
+                                        dynamics.setId(lifeUserDynamic.getId());
+                                        dynamics.setCheckFlag(1);
+                                        dynamics.setAiTaskId(dataNode.get("task_id").toString());
+                                        lifeUserDynamicsMapper.updateById(dynamics);
+                                        log.info("动态审核成功,AI返回内容: {}", response.getBody());
+                                        XxlJobHelper.handleSuccess("动态内容审核任务执行成功");
+                                    }
+                                }else {
+                                    log.error("AI接口调用失败,错误码: " + code);
                                 }
-                                log.info("动态审核成功,AI返回内容: {}", response.getBody());
-                                XxlJobHelper.handleSuccess("动态内容审核任务执行成功");
                             } catch (Exception e) {
                                 log.error("调用AI内容审核接口失败", e);
                             }
@@ -685,6 +683,91 @@ public class AiTagJob {
         return R.success("动态内容审核任务执行成功");
     }
 
+    /**
+     * 获取审核违规内容结果
+     */
+    @XxlJob("getCheckTask")
+    public R<String> getCheckTask() {
+        List<LifeUserDynamics> lifeUserDynamics = lifeUserDynamicsMapper.selectList(new LambdaQueryWrapper<LifeUserDynamics>()
+                .eq(LifeUserDynamics::getCheckFlag, 1).eq(LifeUserDynamics::getDeleteFlag, 0));
+
+        for (LifeUserDynamics lifeUserDynamic : lifeUserDynamics) {
+            try {
+                log.info("登录Ai服务获取token..." + loginUrl);
+                MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+                formData.add("username", userName);
+                formData.add("password", passWord);
+
+                HttpHeaders headers = new HttpHeaders();
+                headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+                HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
+                ResponseEntity<String> postForEntity = null;
+                try {
+                    log.info("请求Ai服务登录接口===================>");
+                    postForEntity = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
+                } catch (Exception e) {
+                    log.error("请求AI服务登录接口失败", e);
+                }
+
+                if (postForEntity != null && postForEntity.getStatusCodeValue() == 200) {
+                    log.info("请求Ai服务登录成功 postForEntity.getBody()\t" + postForEntity.getBody());
+                    String responseBody = postForEntity.getBody();
+                    JSONObject jsonObject = JSONObject.parseObject(responseBody);
+                    if (jsonObject != null) {
+                        JSONObject dataJson = jsonObject.getJSONObject("data");
+                        String accessToken = dataJson.getString("access_token");
+
+                        HttpHeaders aiHeaders = new HttpHeaders();
+                        aiHeaders.setContentType(MediaType.APPLICATION_JSON);
+                        aiHeaders.set("Authorization", "Bearer " + accessToken);
+
+                        Map<String, Object> jsonBody = new HashMap<>();
+                        jsonBody.put("task_id", lifeUserDynamic.getAiTaskId());
+
+                        HttpEntity<Map<String, Object>> request = new HttpEntity<>(jsonBody, aiHeaders);
+                        ResponseEntity<String> response = null;
+                        try {
+                            response = restTemplate.postForEntity(contentComplianceUrl, request, String.class);
+                            if (response.getStatusCodeValue() != 200) {
+                                log.error("AI内容审核结果获取接口调用失败 http状态:" + response.getStatusCode());
+                            }
+                            JSONObject responseNode = JSONObject.parseObject(response.getBody());
+                            if (responseNode == null) {
+                                log.error("AI接口调用失败,响应内容为空");
+                            }
+                            Integer code = null;
+                            if (responseNode != null) {
+                                code = responseNode.getInteger("code");
+                                if(code==200) {
+                                    JSONObject dataNode = JSONObject.from(responseNode.get("data"));
+
+                                    if (!(boolean) dataNode.get("is_compliant")) {
+                                        LifeUserDynamics dynamics = new LifeUserDynamics();
+                                        dynamics.setId(lifeUserDynamic.getId());
+                                        dynamics.setCheckFlag(2);
+                                        dynamics.setEnableStatus(1);
+                                        dynamics.setReason(String.valueOf(dataNode.get("failure_reason")));
+                                        lifeUserDynamicsMapper.updateById(dynamics);
+                                    }
+                                    log.info("动态审核结果获取成功,AI返回内容: {}", response.getBody());
+                                    XxlJobHelper.handleSuccess("动态内容审核任务结果获取执行成功");
+                                } else {
+                                    log.error("AI接口调用失败,错误码: " + code);
+                                }
+                            }
+                        } catch (Exception e) {
+                            log.error("调用AI内容审核结果获取接口失败", e);
+                        }
+                    }
+                }
+            } catch (RuntimeException ex) {
+                XxlJobHelper.handleFail("动态内容审核任务结果获取执行失败:" + ex.getMessage());
+                return R.fail("动态内容审核任务结果获取执行失败:" + ex.getMessage());
+            }
+        }
+        return R.success("动态内容审核任务结果获取执行成功");
+    }
+
     class AnalysisRequest {
         private String start_time;
         private String end_time;
@@ -705,5 +788,4 @@ public class AiTagJob {
             this.end_time = end_time;
         }
     }
-
 }

+ 206 - 0
alien-store/src/main/java/shop/alien/store/controller/LifeUserDynamicsController.java

@@ -1,7 +1,9 @@
 package shop.alien.store.controller;
 
+import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.google.common.collect.Lists;
@@ -9,12 +11,21 @@ import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.client.RestTemplate;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.LifePinglunVo;
 import shop.alien.entity.store.vo.LifeUserDynamicsVo;
+import shop.alien.mapper.LifeUserDynamicsMapper;
 import shop.alien.mapper.LifeUserExpertOrderMapper;
 import shop.alien.mapper.LifeUserExpertWorksMapper;
 import shop.alien.store.service.LifeUserDynamicsService;
@@ -40,6 +51,8 @@ public class LifeUserDynamicsController {
 
     private final LifeUserExpertOrderMapper lifeUserExpertOrderMapper;
 
+    private final LifeUserDynamicsMapper lifeUserDynamicsMapper;
+
 
     @Autowired
     private TextModerationUtil textModerationUtil;
@@ -333,4 +346,197 @@ public class LifeUserDynamicsController {
         }
         return R.success("操作成功");
     }
+
+    @GetMapping("/testAI")
+    public R testAI() {
+        List<LifeUserDynamics> lifeUserDynamics = lifeUserDynamicsMapper.selectList(new LambdaQueryWrapper<LifeUserDynamics>()
+                .eq(LifeUserDynamics::getCheckFlag, 0).eq(LifeUserDynamics::getDeleteFlag, 0));
+
+        // 常见图片后缀(可按需添加,如 .heic、.svg 等)
+        HashSet<String> IMAGE_SUFFIXES = new HashSet<>(Arrays.asList(
+                "jpg", "jpeg", "png", "gif", "bmp", "webp", "heic", "svg", "tiff"
+        ));
+        // 常见视频后缀(可按需添加,如 .avi、.flv 等)
+        HashSet<String> VIDEO_SUFFIXES = new HashSet<>(Arrays.asList(
+                "mp4", "mov", "mkv", "avi", "flv", "wmv", "mpeg", "mpg", "webm"
+        ));
+        RestTemplate restTemplate = new RestTemplate();
+
+        for (LifeUserDynamics lifeUserDynamic : lifeUserDynamics) {
+            String imagePath = lifeUserDynamic.getImagePath();
+
+            List<String> imageList = new ArrayList<>();
+            List<String> videoList = new ArrayList<>();
+            // 按分隔符拆分路径数组(处理连续分隔符如 ",," 产生的空字符串)
+            String[] allPaths = imagePath.split(",");
+            for (String path : allPaths) {
+                // 去除路径前后空格(避免 " a.jpg " 这类情况)
+                String trimmedPath = path.trim();
+                if (trimmedPath.isEmpty()) {
+                    continue; // 跳过空路径
+                }
+                // 获取文件后缀(忽略大小写)
+                // 找到最后一个 "." 的位置
+                int lastDotIndex = trimmedPath.lastIndexOf('.');
+                // 截取后缀(从 "." 后一位到结尾)
+                String suffix = trimmedPath.substring(lastDotIndex + 1);
+                // 分类添加到对应列表
+                if (IMAGE_SUFFIXES.contains(suffix)) {
+                    imageList.add(trimmedPath);
+                } else if (VIDEO_SUFFIXES.contains(suffix)) {
+                    videoList.add(trimmedPath);
+                }
+                try {
+                    log.info("登录Ai服务获取token..." + "http://192.168.2.250:9000/ai/user-auth-core/api/v1/auth/login");
+                    MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+                    formData.add("username", "UdUser");
+                    formData.add("password", "123456");
+
+                    HttpHeaders headers = new HttpHeaders();
+                    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+                    HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
+                    ResponseEntity<String> postForEntity = null;
+                    try {
+                        log.info("请求Ai服务登录接口===================>");
+                        postForEntity = restTemplate.postForEntity("http://192.168.2.250:9000/ai/user-auth-core/api/v1/auth/login", requestEntity, String.class);
+                    } catch (Exception e) {
+                        log.error("请求AI服务登录接口失败", e);
+                    }
+
+                    if (postForEntity != null && postForEntity.getStatusCodeValue() == 200) {
+                        log.info("请求Ai服务登录成功 postForEntity.getBody()\t" + postForEntity.getBody());
+                        String responseBody = postForEntity.getBody();
+                        JSONObject jsonObject = JSONObject.parseObject(responseBody);
+                        if (jsonObject != null) {
+                            JSONObject dataJson = jsonObject.getJSONObject("data");
+                            String accessToken = dataJson.getString("access_token");
+
+                            HttpHeaders aiHeaders = new HttpHeaders();
+                            aiHeaders.setContentType(MediaType.APPLICATION_JSON);
+                            aiHeaders.set("Authorization", "Bearer " + accessToken);
+
+                            Map<String, Object> jsonBody = new HashMap<>();
+                            jsonBody.put("text", lifeUserDynamic.getContext());
+                            jsonBody.put("imgUrl", imageList);
+                            jsonBody.put("video", videoList);
+
+                            HttpEntity<Map<String, Object>> request = new HttpEntity<>(jsonBody, aiHeaders);
+                            ResponseEntity<String> response = null;
+                            try {
+                                response = restTemplate.postForEntity("http://192.168.2.250:9000/ai/auto-review/api/v1/multimodal_audit_task/submit", request, String.class);
+                                if (response.getStatusCodeValue() != 200) {
+                                    log.error("AI内容审核接口调用失败 http状态:" + response.getStatusCode());
+                                }
+                                JSONObject responseNode = JSONObject.parseObject(response.getBody());
+                                if (responseNode == null) {
+                                    log.error("AI接口调用失败,响应内容为空");
+                                }
+                                Integer code = null;
+                                if (responseNode != null) {
+                                    code = responseNode.getInteger("code");
+                                    if(code==200) {
+                                        JSONObject dataNode = JSONObject.from(responseNode.get("data"));
+                                        LifeUserDynamics dynamics = new LifeUserDynamics();
+                                        dynamics.setId(lifeUserDynamic.getId());
+                                        dynamics.setCheckFlag(1);
+                                        dynamics.setAiTaskId(dataNode.get("task_id").toString());
+                                        lifeUserDynamicsMapper.updateById(dynamics);
+                                        log.info("动态审核成功,AI返回内容: {}", response.getBody());
+                                    }
+                                }else {
+                                    log.error("AI接口调用失败,错误码: " + code);
+                                }
+                            } catch (Exception e) {
+                                log.error("调用AI内容审核接口失败", e);
+                            }
+                        }
+                    }
+                } catch (RuntimeException ex) {
+                    return R.fail("动态内容审核任务执行失败:" + ex.getMessage());
+                }
+            }
+        }
+        return R.success("动态内容审核任务执行成功");
+    }
+
+    @GetMapping("/testAIGet")
+    public R testAIGet() {
+        List<LifeUserDynamics> lifeUserDynamics = lifeUserDynamicsMapper.selectList(new LambdaQueryWrapper<LifeUserDynamics>()
+                .eq(LifeUserDynamics::getCheckFlag, 1).eq(LifeUserDynamics::getDeleteFlag, 0));
+        RestTemplate restTemplate = new RestTemplate();
+        for (LifeUserDynamics lifeUserDynamic : lifeUserDynamics) {
+            try {
+                MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+                formData.add("username", "UdUser");
+                formData.add("password", "123456");
+
+                HttpHeaders headers = new HttpHeaders();
+                headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+                HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
+                ResponseEntity<String> postForEntity = null;
+                try {
+                    log.info("请求Ai服务登录接口===================>");
+                    postForEntity = restTemplate.postForEntity("http://192.168.2.250:9000/ai/user-auth-core/api/v1/auth/login", requestEntity, String.class);
+                } catch (Exception e) {
+                    log.error("请求AI服务登录接口失败", e);
+                }
+
+                if (postForEntity != null && postForEntity.getStatusCodeValue() == 200) {
+                    log.info("请求Ai服务登录成功 postForEntity.getBody()\t" + postForEntity.getBody());
+                    String responseBody = postForEntity.getBody();
+                    JSONObject jsonObject = JSONObject.parseObject(responseBody);
+                    if (jsonObject != null) {
+                        JSONObject dataJson = jsonObject.getJSONObject("data");
+                        String accessToken = dataJson.getString("access_token");
+
+                        HttpHeaders aiHeaders = new HttpHeaders();
+                        aiHeaders.setContentType(MediaType.APPLICATION_JSON);
+                        aiHeaders.set("Authorization", "Bearer " + accessToken);
+
+                        Map<String, Object> jsonBody = new HashMap<>();
+                        jsonBody.put("task_id", lifeUserDynamic.getAiTaskId());
+
+                        HttpEntity<Map<String, Object>> request = new HttpEntity<>(jsonBody, aiHeaders);
+                        ResponseEntity<String> response = null;
+                        try {
+                            response = restTemplate.getForEntity("http://192.168.2.250:9000/ai/auto-review/api/v1/multimodal_audit_task/getResult?task_id="+lifeUserDynamic.getAiTaskId(), String.class);
+                            if (response.getStatusCodeValue() != 200) {
+                                log.error("AI内容审核结果获取接口调用失败 http状态:" + response.getStatusCode());
+                            }
+                            JSONObject responseNode = JSONObject.parseObject(response.getBody());
+                            if (responseNode == null) {
+                                log.error("AI接口调用失败,响应内容为空");
+                            }
+                            Integer code = null;
+                            if (responseNode != null) {
+                                code = responseNode.getInteger("code");
+                                if(code==200) {
+                                    JSONObject dataNode = JSONObject.from(responseNode.get("data"));
+
+                                    if (!(boolean) dataNode.get("is_compliant")) {
+                                        LifeUserDynamics dynamics = new LifeUserDynamics();
+                                        dynamics.setId(lifeUserDynamic.getId());
+                                        dynamics.setCheckFlag(2);
+                                        dynamics.setEnableStatus(1);
+                                        dynamics.setReason(String.valueOf(dataNode.get("failure_reason")));
+                                        lifeUserDynamicsMapper.updateById(dynamics);
+                                    }
+                                    log.info("动态审核结果获取成功,AI返回内容: {}", response.getBody());
+//                                    XxlJobHelper.handleSuccess("动态内容审核任务结果获取执行成功");
+                                } else {
+                                    log.error("AI接口调用失败,错误码: " + code);
+                                }
+                            }
+                        } catch (Exception e) {
+                            log.error("调用AI内容审核结果获取接口失败", e);
+                        }
+                    }
+                }
+            } catch (RuntimeException ex) {
+//                XxlJobHelper.handleFail("动态内容审核任务结果获取执行失败:" + ex.getMessage());
+                return R.fail("动态内容审核任务结果获取执行失败:" + ex.getMessage());
+            }
+        }
+        return R.success("动态内容审核任务结果获取执行成功");
+    }
 }