Ver Fonte

文本,图片内容检测工具类

hulin há 2 dias atrás
pai
commit
370eb18dd8

+ 319 - 0
fs-user-app/src/main/java/com/fs/app/utils/ContentCheckUtil.java

@@ -0,0 +1,319 @@
+package com.fs.app.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.core.domain.R;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.function.Supplier;
+
+/**
+ * 内容审核
+ */
+@Slf4j
+public final class ContentCheckUtil {
+
+    private static final OkHttpClient client = new OkHttpClient();
+
+    private static final String HOST_TEXT = "tms.tencentcloudapi.com";
+
+    private static final String HOST_IMG = "ims.tencentcloudapi.com";
+
+    private static final String SECRET_ID = "AKID0tdCbmiT3Qis6A2hARVMl3A6tTu9CmIg";
+
+    private static final String SECRET_KEY = "JQN8h4HJHbqtvnR3Xp9GI8mGpBNRQDvV";
+
+    private static final char[] HEX_CODE = "0123456789ABCDEF".toCharArray();
+
+    private static final String SUGGESTION_PASS = "Pass";
+
+    private static final String SUGGESTION_REVIEW = "Review";
+
+    private static final String SUGGESTION_BLOCK = "Block";
+
+    private static final String DEFAULT_REGION = "ap-beijing";
+
+    private static final Map<String, String> SUGGESTION_MAP = new HashMap<>();
+
+    private static final Map<String, String> LABEL_MAP = new HashMap<>();
+
+    static {
+        SUGGESTION_MAP.put("Block", "建议直接做违规处置");
+        SUGGESTION_MAP.put("Review", "建议人工二次确认");
+        SUGGESTION_MAP.put("Pass", "建议通过");
+        LABEL_MAP.put("Normal", "正常");
+        LABEL_MAP.put("Porn", "色情");
+        LABEL_MAP.put("Abuse", "谩骂");
+        LABEL_MAP.put("Ad", "广告;以及其他令人反感、不安全或不适宜的内容类型");
+        LABEL_MAP.put("Illegal", "非法的");
+        LABEL_MAP.put("Teenager", "青少年");
+    }
+
+//    public static void main(String[] args) {
+//        R r = checkText("操你妈");
+//        log.info("{}", r);
+//        R r1 = checkImage("https://cdn.his.cdwjyyh.com/fs/20260320/989bf692ddd0465cb363f514a1576454.png");
+//        System.out.println(r1);
+//        log.info("{}", r1);
+//    }
+
+    /**
+     * 文本违规审核
+     *
+     * @param text 待审核内容
+     */
+    public static R checkText(String text) {
+        return checkText(text, DEFAULT_REGION);
+    }
+
+    /**
+     * 图片违规审核内容
+     *
+     * @param fileUrl 图片所在网络地址
+     */
+    public static R checkImage(String fileUrl) {
+        return checkImage(fileUrl, DEFAULT_REGION);
+    }
+
+    /**
+     * 文本违规审核
+     *
+     * @param text   待审核内容
+     * @param region 区域
+     */
+    public static R checkText(String text, String region) {
+        String version = "2020-12-29";
+        String action = "TextModeration";
+        // 用Supplier封装文本审核的请求体构建逻辑(函数式编程核心)
+        Supplier<String> bodySupplier = () -> {
+            JSONObject obj = new JSONObject();
+            obj.put("BizType", "text");
+            obj.put("Content", Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8)));
+            return obj.toJSONString();
+        };
+        return commonModeration(HOST_TEXT, version, action, bodySupplier, region, "文本审核未通过!");
+    }
+
+    /**
+     * 图片违规审核
+     *
+     * @param fileUrl 图片所在网络地址
+     * @param region  区域
+     */
+    public static R checkImage(String fileUrl, String region) {
+        String version = "2020-12-29";
+        String action = "ImageModeration";
+        // 用Supplier封装图片审核的请求体构建逻辑
+        Supplier<String> bodySupplier = () -> {
+            JSONObject obj = new JSONObject();
+            obj.put("BizType", "picture");
+            obj.put("DataId", UUID.randomUUID().toString());
+            obj.put("FileUrl", fileUrl);
+            return obj.toJSONString();
+        };
+        return commonModeration(HOST_IMG, version, action, bodySupplier, region, "图片审核未通过!");
+    }
+
+
+    /**
+     * 通用审核方法
+     *
+     * @param host         接口域名
+     * @param version      接口版本
+     * @param action       接口动作
+     * @param bodySupplier 请求体构建器
+     * @param region       区域
+     * @param failMsg      审核失败提示语
+     * @return 审核结果R
+     */
+    private static R commonModeration(
+            String host,
+            String version,
+            String action,
+            Supplier<String> bodySupplier,
+            String region,
+            String failMsg) {
+        try {
+            // 构建请求
+            Request request = buildRequest(host, SECRET_ID, SECRET_KEY, version, action, bodySupplier.get(), region, "");
+            Response response = client.newCall(request).execute();
+
+            // 处理响应
+            if (response.isSuccessful() && null != response.body()) {
+                String respBody = response.body().string();
+                log.info("审核结果:{}", respBody);
+                ResponseResult responseResult = JSONObject.parseObject(respBody, ResponseResult.class);
+
+                // 判断审核结果
+                if (responseResult.getResponse().getSuggestion().equals(SUGGESTION_PASS)) {
+                    return R.ok().put("success", true);
+                } else {
+                    Map<String, Object> checkDetail = new HashMap<>();
+                    checkDetail.put("Suggestion", SUGGESTION_MAP.get(responseResult.getResponse().getSuggestion()));
+                    checkDetail.put("Type", LABEL_MAP.get(responseResult.getResponse().getLabel()));
+                    return R.error(failMsg)
+                            .put("checkDetail", checkDetail)
+                            .put("success", false);
+                }
+            } else {
+                return R.error(failMsg.replace("未通过", "失败") + "!!")
+                        .put("success", false);
+            }
+        } catch (Exception e) {
+            log.error("{}:", failMsg.replace("未通过", "失败"), e);
+            return R.error(e.getMessage())
+                    .put("success", false);
+        }
+    }
+
+    /**
+     * 构建请求信息
+     *
+     * @param host      主机信息
+     * @param secretId  密钥id
+     * @param secretKey 密钥key
+     * @param version   api版本
+     * @param action    公共参数
+     * @param body      请求体
+     * @param region    地区
+     * @param token     令牌
+     */
+    public static Request buildRequest(
+            String host, String secretId, String secretKey,
+            String version, String action,
+            String body, String region, String token
+    ) throws NoSuchAlgorithmException, InvalidKeyException {
+        String endpoint = "https://" + host;
+        String contentType = "application/json; charset=utf-8";
+        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+        String auth = getAuth(secretId, secretKey, host, contentType, timestamp, body);
+        return new Request.Builder()
+                .header("Host", host)
+                .header("X-TC-Timestamp", timestamp)
+                .header("X-TC-Version", version)
+                .header("X-TC-Action", action)
+                .header("X-TC-Region", region)
+                .header("X-TC-Token", token)
+                .header("X-TC-RequestClient", "SDK_JAVA_BAREBONE")
+                .header("Authorization", auth)
+                .url(endpoint)
+                .post(RequestBody.create(MediaType.parse(contentType), body))
+                .build();
+    }
+
+    /**
+     * 获取签名
+     *
+     * @param secretId    密钥id
+     * @param secretKey   密钥key
+     * @param host        主机信息
+     * @param contentType 内容类型
+     * @param timestamp   时间戳
+     * @param body        加密内容
+     */
+    private static String getAuth(
+            String secretId, String secretKey, String host, String contentType,
+            String timestamp, String body
+    ) throws NoSuchAlgorithmException, InvalidKeyException {
+        String canonicalUri = "/";
+        String canonicalQueryString = "";
+        String canonicalHeaders = "content-type:" + contentType + "\nhost:" + host + "\n";
+        String signedHeaders = "content-type;host";
+        String hashedRequestPayload = sha256Hex(body.getBytes(StandardCharsets.UTF_8));
+        String canonicalRequest = "POST"
+                + "\n"
+                + canonicalUri
+                + "\n"
+                + canonicalQueryString
+                + "\n"
+                + canonicalHeaders
+                + "\n"
+                + signedHeaders
+                + "\n"
+                + hashedRequestPayload;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+        String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
+        String service = host.split("\\.")[0];
+        String credentialScope = date + "/" + service + "/" + "tc3_request";
+        String hashedCanonicalRequest =
+                sha256Hex(canonicalRequest.getBytes(StandardCharsets.UTF_8));
+        String stringToSign =
+                "TC3-HMAC-SHA256\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
+        byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(StandardCharsets.UTF_8), date);
+        byte[] secretService = hmac256(secretDate, service);
+        byte[] secretSigning = hmac256(secretService, "tc3_request");
+        String signature =
+                printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
+        return "TC3-HMAC-SHA256 "
+                + "Credential="
+                + secretId
+                + "/"
+                + credentialScope
+                + ", "
+                + "SignedHeaders="
+                + signedHeaders
+                + ", "
+                + "Signature="
+                + signature;
+    }
+
+    /*
+
+     */
+    public static String sha256Hex(byte[] b) throws NoSuchAlgorithmException {
+        MessageDigest md;
+        md = MessageDigest.getInstance("SHA-256");
+        byte[] d = md.digest(b);
+        return printHexBinary(d).toLowerCase();
+    }
+
+    public static String printHexBinary(byte[] data) {
+        StringBuilder r = new StringBuilder(data.length * 2);
+        for (byte b : data) {
+            r.append(HEX_CODE[(b >> 4) & 0xF]);
+            r.append(HEX_CODE[(b & 0xF)]);
+        }
+        return r.toString();
+    }
+
+    public static byte[] hmac256(byte[] key, String msg) throws NoSuchAlgorithmException, InvalidKeyException {
+        Mac mac = Mac.getInstance("HmacSHA256");
+        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
+        mac.init(secretKeySpec);
+        return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
+    }
+
+    @Data
+    public static class ResponseResult {
+
+        private Integer retcode;
+
+        private String retmsg;
+
+        private CheckResponse Response;
+
+    }
+
+    @Data
+    public static class CheckResponse {
+
+        private String RequestId;
+
+        private String BizType;
+
+        private String Label;
+
+        private String Suggestion;
+
+    }
+}