You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
11 KiB

package com.youlai.boot.common.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.util.List;
import com.aliyun.green20220302.Client;
import com.aliyun.green20220302.models.*;
import com.aliyun.teaopenapi.models.Config;
import com.youlai.boot.common.exception.MsgException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 阿里云内容安全统一审核工具类v2.0
* ----------------------------------------
* 支持
* 1. 文本审核
* 2. 图片审核
* 3. 视频审核异步
* 4. 取消视频审核任务直播流
*
* 特性
* - 自动切换备用节点cn-beijing
* - application.yml 中读取配置
* - 返回 null 表示请求失败业务层自行判断
*/
@Slf4j
@Component
public class AliyunContentAuditUtil {
@Value("${audit.aliyun.green.accessKeyId}")
private String accessKeyId;
@Value("${audit.aliyun.green.accessKeySecret}")
private String accessKeySecret;
// 主节点(上海)
private static final String REGION_PRIMARY = "cn-shanghai";
private static final String ENDPOINT_PRIMARY = "green-cip.cn-shanghai.aliyuncs.com";
// 备用节点(北京)
private static final String REGION_BACKUP = "cn-beijing";
private static final String ENDPOINT_BACKUP = "green-cip.cn-beijing.aliyuncs.com";
// 批量审核上限
private static final int BATCH_TEXT_MAX = 100;
private static final int BATCH_TEXT_SINGLE_MAX_CHARS = 600;
/**
* 构建客户端
*/
private Client createClient(boolean useBackup) throws Exception {
String region = useBackup ? REGION_BACKUP : REGION_PRIMARY;
String endpoint = useBackup ? ENDPOINT_BACKUP : ENDPOINT_PRIMARY;
Config config = new Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret)
.setRegionId(region)
.setEndpoint(endpoint)
.setReadTimeout(6000)
.setConnectTimeout(3000);
return new Client(config);
}
/**
* 自动调用机制
* - 优先使用上海节点
* - 如果响应码为 500 或出现异常自动切换至北京节点重试一次
*/
private <T> T executeWithFailover(AliyunRequestExecutor<T> executor) {
try {
Client primary = createClient(false);
T result = executor.execute(primary);
if (isServerError(result)) {
log.warn("阿里云内容安全服务端异常,切换到北京节点重试...");
Client backup = createClient(true);
return executor.execute(backup);
}
return result;
} catch (Exception e) {
log.error("阿里云内容安全调用异常(主节点失败),切换至备用节点", e);
try {
Client backup = createClient(true);
return executor.execute(backup);
} catch (Exception ex) {
log.error("备用节点调用也失败", ex);
return null;
}
}
}
/**
* 判断是否服务端异常statusCode=500
*/
private boolean isServerError(Object response) {
try {
Integer code = (Integer) response.getClass().getMethod("getStatusCode").invoke(response);
return code != null && code == 500;
} catch (Exception ignored) {
return false;
}
}
// ===================== 文本审核 =====================
public TextModerationResponse textModeration(String content) {
return executeWithFailover(client -> {
JSONObject params = new JSONObject();
params.put("content", content);
TextModerationRequest request = new TextModerationRequest()
.setService("comment_detection")
.setServiceParameters(params.toJSONString());
return client.textModeration(request);
});
}
/**
* 批量文本审核上限100条单条不超过600字
*/
public TextModerationResponse batchTextModeration(List<String> contents) {
if (contents == null || contents.isEmpty()) {
return null;
}
if (contents.size() > BATCH_TEXT_MAX) {
throw new MsgException("批量文本审核单次上限" + BATCH_TEXT_MAX + "条,当前" + contents.size() + "条");
}
for (int i = 0; i < contents.size(); i++) {
String text = contents.get(i);
if (text != null && text.length() > BATCH_TEXT_SINGLE_MAX_CHARS) {
throw new MsgException("第" + (i + 1) + "条文本超过" + BATCH_TEXT_SINGLE_MAX_CHARS + "字上限");
}
}
return executeWithFailover(client -> {
JSONObject params = new JSONObject();
JSONArray arr = new JSONArray();
arr.addAll(contents);
params.put("content", arr);
TextModerationRequest request = new TextModerationRequest()
.setService("comment_detection")
.setServiceParameters(params.toJSONString());
return client.textModeration(request);
});
}
// ===================== 文本审核Plus =====================
//nickname_detection_pro 用户昵称检测_专业版(用户昵称) ;ugc_moderation_byllm_pro UGC场景文本审核大模型服务_专业版(个人简介 / 作品内容) ;
//comment_detection_pro 公聊评论内容检测_专业版(评论); ugc_moderation_byllm UGC场景文本审核大模型服务 (作品标题)
public TextModerationPlusResponse textModerationPlus(String content) {
return executeWithFailover(client -> {
JSONObject params = new JSONObject();
params.put("content", content);
TextModerationPlusRequest textModerationPlusRequest = new TextModerationPlusRequest()
.setService("ugc_moderation_byllm_pro")
.setServiceParameters(params.toJSONString());
return client.textModerationPlus(textModerationPlusRequest);
});
}
/**
* 批量文本审核Plus上限100条单条不超过600字
*/
public TextModerationPlusResponse batchTextModerationPlus(List<String> contents) {
if (contents == null || contents.isEmpty()) {
return null;
}
if (contents.size() > BATCH_TEXT_MAX) {
throw new MsgException("批量文本审核单次上限" + BATCH_TEXT_MAX + "条,当前" + contents.size() + "条");
}
for (int i = 0; i < contents.size(); i++) {
String text = contents.get(i);
if (text != null && text.length() > BATCH_TEXT_SINGLE_MAX_CHARS) {
throw new MsgException("第" + (i + 1) + "条文本超过" + BATCH_TEXT_SINGLE_MAX_CHARS + "字上限");
}
}
return executeWithFailover(client -> {
JSONObject params = new JSONObject();
JSONArray arr = new JSONArray();
arr.addAll(contents);
params.put("content", arr);
TextModerationPlusRequest request = new TextModerationPlusRequest()
.setService("ugc_moderation_byllm_pro")
.setServiceParameters(params.toJSONString());
return client.textModerationPlus(request);
});
}
// ===================== 图片审核 =====================
// 头像图片检测:profilePhotoCheck (头像) ; AI生成图片鉴别_含隐式标识版:aigcDetectorFull(AI生成图片) ;
// 大小模型融合图片审核服务:postlmageCheckByVL (用户上传的图片) ; OSS基线检测(OSS普惠版专用):oss_baselineCheck
// 通用图片审核大模型服务:baselineCheckByVL(用户作品);图片万物识别:generalRecognition ;营销素材检测:advertisingCheck
public ImageModerationResponse imageModeration(String imageUrl) {
return executeWithFailover(client -> {
JSONObject params = new JSONObject();
params.put("imageUrl", imageUrl);
ImageModerationRequest request = new ImageModerationRequest()
.setService("oss_baselineCheck")
.setServiceParameters(params.toJSONString());
return client.imageModeration(request);
});
}
// 图片审核不支持批量,使用 imageModeration 逐个调用
// ===================== 视频审核(异步) =====================
//视频文件检测:videoDetection ; AI生成视频判定:videoAigcDetector ; 视频文件检测_大模型版:videoDetectionByVL
public VideoModerationResponse videoModeration(String videoUrl) {
return executeWithFailover(client -> {
JSONObject params = new JSONObject();
params.put("url", videoUrl);
VideoModerationRequest request = new VideoModerationRequest()
.setService("videoDetection")
.setServiceParameters(params.toJSONString());
return client.videoModeration(request);
});
}
// 视频审核不支持批量,使用 videoModeration 逐个调用
// ===================== 查询视频审核结果 =====================
public VideoModerationResultResponse videoModerationResult(String taskId) {
return executeWithFailover(client -> {
JSONObject params = new JSONObject();
params.put("taskId", taskId);
VideoModerationResultRequest request = new VideoModerationResultRequest()
.setService("videoDetection")
.setServiceParameters(params.toJSONString());
return client.videoModerationResult(request);
});
}
// ===================== 取消视频直播流检测任务 =====================
public VideoModerationCancelResponse cancelVideoTask(String taskId) {
return executeWithFailover(client -> {
JSONObject params = new JSONObject();
params.put("taskId", taskId);
VideoModerationCancelRequest request = new VideoModerationCancelRequest()
.setService("liveStreamDetection")
.setServiceParameters(params.toJSONString());
return client.videoModerationCancel(request);
});
}
/**
* 函数式接口用于统一封装 SDK 调用逻辑
*/
@FunctionalInterface
private interface AliyunRequestExecutor<T> {
T execute(Client client) throws Exception;
}
}