今日主要就是一个阿里云sdk v2的升级,别的也没有什么,本文代码均为参照官网文档以及尽可能的贴近原项目代码sdk v1写法,哦对了,增强版不用企业认证,个人注册按量付费,应该不贵,用来测试很好
官网奉上,图片自动审核也在里面
如何使用文本审核增强版识别文本违规风险_内容安全(Content Moderation)-阿里云帮助中心
阿里云内容安全服务sdk v2
nacos中的相关配置
我本以为,有了minio,就不用oss了,结果还是用了
aliyun:
text:
accessKeyId: YouraccessKeyId
secret: Yoursecret
service: comment_detection
region: cn-shanghai
endpoint: green-cip.cn-shanghai.aliyuncs.com
image:
accessKeyId: YouraccessKeyId
secret: YouraccessKeyId
scenes: terrorism
#aliyun.scenes=porn,terrorism,ad,qrcode,live,logo
service: baselineCheck
region: "cn-shanghai"
endpoint: green-cip.cn-shanghai.aliyuncs.com
ossEndpoint: oss-cn-beijing.aliyuncs.com
ossBucket: YourBucketName
为什么要区分text以及image,因为配置prefix全部等于aliyun会爆前缀重复的错,所以我加了一点
关于两边的service参数,我感觉以后有用,所以我截图了
文本:
图片:
就是根据不同的场景去调整参数就行
依赖引入
<!–增强版阿里云内容安全–>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>green20220302</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
依赖一个是增强版内容安全的,一个是oss的,注意oss的版本,如果版本低一点可能会导致后面业务代码中OSSClientBuilder爆错
业务代码
把这两个业务代码给原来代码里的两个替换掉即可,记得改一下spring.facotories
文本自动审核
实际干活的方法是moderate,传String content即可
package com.heima.common.aliyun;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.green20220302.Client;
import com.aliyun.green20220302.models.TextModerationRequest;
import com.aliyun.green20220302.models.TextModerationResponse;
import com.aliyun.green20220302.models.TextModerationResponseBody;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Getter
@Setter
@Slf4j
@Component
@ConfigurationProperties(prefix = "aliyun.text")
public class GreenTextModeration {
/** 从配置文件读取 */
private String accessKeyId;
private String secret;
private String region;
private String endpoint;
private String service;
private Client client;
public void initClient() throws Exception {
Config config = new Config();
config.setAccessKeyId(accessKeyId);
config.setAccessKeySecret(secret);
config.setRegionId(region);
config.setEndpoint(endpoint);
config.setConnectTimeout(3000);
config.setReadTimeout(6000);
client = new Client(config);
log.info("Aliyun Green client initialized, endpoint={}, region={}", endpoint, region);
}
/**
* 审核文本
* @param content 待检测文本
* @return suggestion: pass/review/block; label: 命中类型
*/
public Map<String, String> moderate(String content) throws Exception {
initClient();
Map<String, String> resultMap = new HashMap<>();
if (content == null || content.trim().isEmpty()) {
resultMap.put("suggestion", "pass");
return resultMap;
}
try {
JSONObject serviceParameters = new JSONObject();
serviceParameters.put("content", content);
serviceParameters.put("dataId", UUID.randomUUID().toString());
TextModerationRequest req = new TextModerationRequest();
req.setService(service);
req.setServiceParameters(serviceParameters.toJSONString());
RuntimeOptions runtime = new RuntimeOptions();
runtime.readTimeout = 10000;
runtime.connectTimeout = 10000;
TextModerationResponse response = client.textModerationWithOptions(req, runtime);
if (response == null || response.getStatusCode() != 200) {
log.warn("textModeration failed or status != 200");
return null;
}
TextModerationResponseBody body = response.getBody();
log.warn("Full response body: {}", JSON.toJSONString(body, true));
if (body != null && body.getCode() != null && body.getCode() == 200) {
TextModerationResponseBody.TextModerationResponseBodyData data = body.getData();
String labels = data.getLabels();
if (labels != null && !labels.trim().isEmpty() && !"[]".equals(labels.trim())) {
resultMap.put("suggestion", "block");
resultMap.put("label", labels);
} else {
resultMap.put("suggestion", "pass");
}
return resultMap;
} else {
log.warn("textModeration code != 200");
return null;
}
} catch (Exception e) {
log.error("text moderation error", e);
return null;
}
}
}
图片自动审核
package com.heima.common.aliyun;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.green20220302.Client;
import com.aliyun.green20220302.models.ImageModerationRequest;
import com.aliyun.green20220302.models.ImageModerationResponse;
import com.aliyun.green20220302.models.ImageModerationResponseBody;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.ByteArrayInputStream;
import java.util.*;
@Slf4j
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "aliyun.image")
public class GreenImageModeration {
// 绿网配置
private String accessKeyId;
private String secret;
private String region;
private String endpoint;
private String service;
private String scenes;
private Client client;
// 阿里云OSS配置
private String ossEndpoint;
private String ossBucket;
private OSS ossClient;
public void initClient() throws Exception {
// 初始化绿网Client
Config config = new Config();
config.setAccessKeyId(accessKeyId);
config.setAccessKeySecret(secret);
config.setRegionId(region);
config.setEndpoint(endpoint);
client = new Client(config);
// 初始化OSS客户端
ossClient = new OSSClientBuilder().build(ossEndpoint, accessKeyId,secret);
log.info("Initialized clients: GreenImageModeration service={} region={}, OSS endpoint={}", service, region, ossEndpoint);
}
/**
* 上传图片二进制到OSS,返回图片公网访问URL
*/
public String uploadImageToOss(byte[] imageBytes, String objectName) {
try {
ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
ossClient.putObject(ossBucket, objectName, inputStream);
// 拼接公网URL,假设Bucket开启了公网读权限
String url = "https://" + ossBucket + "." + ossEndpoint + "/" + objectName;
return url;
} catch (Exception e) {
log.error("Upload image to OSS failed", e);
return null;
}
}
/**
* 图片审核(使用URL方式)
* 先上传图片到OSS,再用图片URL调用绿网接口
* @param imageList 图片字节数组列表
* @return 审核结果 Map
*/
public Map<String, String> moderateImage(List<byte[]> imageList) throws Exception {
initClient();
Map<String, String> resultMap = new HashMap<>();
for (int i = 0; i < imageList.size(); i++) {
byte[] imageBytes = imageList.get(i);
String objectName = "image-moderation/" + UUID.randomUUID().toString() + ".jpg"; // 自定义路径及名称
// 1. 上传图片到OSS,获取URL
String imageUrl = uploadImageToOss(imageBytes, objectName);
if (imageUrl == null) {
log.error("Upload image to OSS failed for image index {}", i);
resultMap.put("suggestion", "upload_failed");
continue;
}
// 2. 构造绿网审核请求参数,使用URL方式
JSONObject params = new JSONObject();
params.put("dataId", UUID.randomUUID().toString());
params.put("imageUrl", imageUrl); // 这里改用URL传参
params.put("scenes", Arrays.asList(scenes.split(",")));
ImageModerationRequest req = new ImageModerationRequest();
req.setService(service);
req.setServiceParameters(params.toJSONString());
RuntimeOptions runtime = new RuntimeOptions();
runtime.connectTimeout = 10000;
runtime.readTimeout = 10000;
ImageModerationResponse resp = client.imageModerationWithOptions(req, runtime);
if (resp == null || resp.getStatusCode() != 200) {
log.error("ImageModeration HTTP error, status: {}", resp == null ? "null" : resp.getStatusCode());
resultMap.put("suggestion", "http_error");
continue;
}
ImageModerationResponseBody body = resp.getBody();
log.warn("Full response body: {}", JSON.toJSONString(body, true));
if (body.getCode() != null && body.getCode() == 200) {
ImageModerationResponseBody.ImageModerationResponseBodyData data = body.getData();
if (data == null || data.getResult() == null || data.getResult().isEmpty()) {
log.warn("No moderation results returned");
resultMap.put("suggestion", "pass");
continue;
}
ImageModerationResponseBody.ImageModerationResponseBodyDataResult first = data.getResult().get(0);
String label = first.getLabel();
Float confidence = first.getConfidence();
String suggestion;
if ("nonLabel".equals(label) || label == null || label.isEmpty()) {
suggestion = "pass";
} else {
suggestion = "block";
}
resultMap.put("suggestion", suggestion);
resultMap.put("label", label != null ? label : "");
resultMap.put("confidence", confidence != null ? confidence.toString() : "");
log.warn("Moderation result: suggestion={}, label={}, confidence={}", suggestion, label, confidence);
} else {
log.error("Moderation failed: code={}, msg={}", body.getCode(), body.getMsg());
resultMap.put("suggestion", "fail");
}
}
return resultMap;
}
// 关闭OSS客户端时机请根据项目需求调整
public void shutdown() {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
解释一下为什么用oss:因为minio的图片访问路径不是公网路径,而阿里云内容安全服务传的图片url他又要求是公网url,所以业务逻辑实际上是先从minio中下载对应的图片然后上传到oss里(我把之前做tlias的Bucket拿来用了)
这个里面干活的方法是moderateImage,传List<byte[]> imageList
两个业务实现逻辑就跟原来的基本一模一样了,以上
评论前必须登录!
注册