package com.ruoyi.common.utils;

/**
 * @Author: tjf
 * @Date: 2024/4/17 9:35
 * @Describe:
 */

import com.alibaba.fastjson2.JSONArray;
import com.aliyun.cloudauth20190307.Client;
import com.aliyun.cloudauth20190307.models.*;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;

import java.util.Arrays;
import java.util.List;

import cn.hutool.http.HttpUtil;

import java.util.Arrays;
import java.util.List;

import com.aliyun.cloudauth20190307.Client;
import com.aliyun.cloudauth20190307.models.*;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.ruoyi.common.core.domain.SysUserIdcardVo;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import okhttp3.*;
import org.apache.poi.util.IOUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

import static com.ruoyi.common.constant.CommonConstants.*;

public class IdCardUtil {
    /**
     * 重要提示代码中所需工具类
     * FileUtil,HttpUtil请从
     * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
     * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
     * 下载
     * <p>
     * https://cloud.baidu.com/doc/OCR/s/rk3h7xzck 文档地址
     */

    // aes key 从console控制台获取 身份证识别使用
    static String aesKey = "ce539dc069ad0908";

    static byte[] originAesKey = null;

    /**
     * 身份证识别
     * {
     * "log_id": "1559208562721579319",
     * "direction": 0,
     * "image_status": "normal",
     * "photo": "/9j/4AAQSkZJRgABA......",
     * "photo_location": {
     * "width": 1189,
     * "top": 638,
     * "left": 2248,
     * "height": 1483
     * },
     * "card_image": "/9j/4AAQSkZJRgABA......",
     * "card_location": {
     * "top": 328,
     * "left": 275,
     * "width": 1329,
     * "height": 571
     * },
     * "words_result": {
     * "住址": {
     * "location": {
     * "left": 267,
     * "top": 453,
     * "width": 459,
     * "height": 99
     * },
     * "words": "南京市江宁区弘景大道3889号"
     * },
     * "公民身份号码": {
     * "location": {
     * "left": 443,
     * "top": 681,
     * "width": 589,
     * "height": 45
     * },
     * "words": "330881199904173914"
     * },
     * "出生": {
     * "location": {
     * "left": 270,
     * "top": 355,
     * "width": 357,
     * "height": 45
     * },
     * "words": "19990417"
     * },
     * "姓名": {
     * "location": {
     * "left": 267,
     * "top": 176,
     * "width": 152,
     * "height": 50
     * },
     * "words": "伍云龙"
     * },
     * "性别": {
     * "location": {
     * "left": 269,
     * "top": 262,
     * "width": 33,
     * "height": 52
     * },
     * "words": "男"
     * },
     * "民族": {
     * "location": {
     * "left": 492,
     * "top": 279,
     * "width": 30,
     * "height": 37
     * },
     * "words": "汉"
     * }
     * },
     * "words_result_num": 6
     * }
     * <p>
     * <p>
     * {
     * "words_result": {
     * "失效日期": {
     * "words": "20390711",
     * "location": {
     * "top": 445,
     * "left": 523,
     * "width": 153,
     * "height": 38
     * }
     * },
     * "签发机关": {
     * "words": "陆丰市公安局",
     * "location": {
     * "top": 377,
     * "left": 339,
     * "width": 195,
     * "height": 38
     * }
     * },
     * "签发日期": {
     * "words": "20190606",
     * "location": {
     * "top": 445,
     * "left": 343,
     * "width": 152,
     * "height": 38
     * }
     * }
     * },
     * "log_id": "1559208562721579328",
     * "words_result_num": 3,
     * "error_code": 0,
     * "image_status": "normal"
     * }
     *
     * @return
     */
    public static AjaxResult idCard(String image, String idCardSide) {
        try {
            // 文件路径
            byte[] imgData = FileUtil.readFileByBytes(image);

            String imgStr = encryptImg(aesKey, imgData);

            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
            String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard";
            //-front：身份证含照片的一面
            //-back：身份证带国徽的一面
            //自动检测身份证正反面，如果传参指定方向与图片相反，支持正常识别，返回参数image_status字段为"reversed_side"
            String param = "id_card_side=" + idCardSide +
                    "&image=" + imgParam +
                    "&AESEncry=" + true;
            String accessToken = getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK");
            String encryptResult = HttpUtils.post(url, accessToken, param);
            String decryptResult = parseResult(encryptResult);
            JSONObject jsonObject = JSON.parseObject(decryptResult);
            String wordsResult = jsonObject.getString("words_result");
            Map<String, Object> map = new HashMap<>(3);
            if (StringUtils.isNotEmpty(wordsResult)) {
                JSONObject jsonObjectWordsResult = JSON.parseObject(wordsResult);
                if (FRONT.equals(idCardSide)) {
                    String name = JSON.parseObject(jsonObjectWordsResult.getString("姓名")).getString("words");
                    String address = JSON.parseObject(jsonObjectWordsResult.getString("住址")).getString("words");
                    String idCard = JSON.parseObject(jsonObjectWordsResult.getString("公民身份号码")).getString("words");
                    map.put("realName", name);
                    map.put("address", address);
                    map.put("idCard", idCard);
                } else if (BACK.equals(idCardSide)) {
                    String date = JSON.parseObject(jsonObjectWordsResult.getString("失效日期")).getString("words");
                    map.put("expirationDate", date);
                }
            }
            return AjaxResult.success(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.error();
    }

    /**
     * 加密图片
     *
     * @param aesKey
     * @param imgData
     * @return
     * @throws Exception
     */
    private static String encryptImg(String aesKey, byte[] imgData) throws Exception {
        originAesKey = AesKeyUtil.parseAesKey(aesKey);
        byte[] encImgBytes = AesUtil.encrypt(imgData, originAesKey);
        String imgStr = Base64Util.encodeBase64(encImgBytes);
        return imgStr;
    }

    /**
     * 解密结果
     *
     * @param encryptResult
     * @return
     * @throws Exception
     */
    private static String parseResult(String encryptResult) throws Exception {
        JSONObject obj = JSONObject.parseObject(encryptResult);
        String result = obj.getString("result");
        byte[] arr = Base64Util.decodeBase64(result);
        String decryptResult = new String(AesUtil.decrypt(arr, originAesKey));
        return decryptResult;
    }


    static class AesKeyUtil {
        private static final String HEX = "0123456789abcdef";

        /**
         * 获得原生的128位的aeskey
         * 因为一个byte位8位最后生成的byte数组长度为16
         * <p>
         * 16 * 8 = 128
         *
         * @param hex
         * @return
         */
        public static byte[] parseAesKey(String hex) throws Exception {
            char[] data = hex.toCharArray();
            if (data.length != 16) {
                throw new Exception(" ase key illegal ");
            }
            return decode(hex.toCharArray());
        }

        private static byte[] decode(char[] data) throws IllegalArgumentException {
            int len = data.length;

            byte[] out = new byte[len];

            for (int i = 0; i < len; i++) {
                int f = toDigit(data[i]);
                out[i] = (byte) (f);
            }
            return out;
        }

        private static int toDigit(char ch) {
            return HEX.indexOf(ch);
        }
    }

    static class AesUtil {

        private static final String ALGORITHM = "AES";

        private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";

        /**
         * aes 加密
         */
        private static byte[] encrypt(byte[] src, byte[] aesKey) throws Exception {
            Cipher cipher = getCipher(aesKey, Cipher.ENCRYPT_MODE);
            byte[] ret = cipher.doFinal(src);
            return ret;
        }

        /**
         * aes 解密
         */
        public static byte[] decrypt(byte[] src, byte[] aesKey) throws Exception {
            Cipher cipher = getCipher(aesKey, Cipher.DECRYPT_MODE);
            byte[] original = cipher.doFinal(src);
            return original;
        }

        private static Cipher getCipher(byte[] aesKey, int mode) throws Exception {
            SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
            cipher.init(mode, secretKeySpec);
            return cipher;
        }
    }

    static class Base64Util {

        private static Base64.Encoder ENCODER = Base64.getEncoder();

        // base64 加密
        private static Base64.Decoder DECODER = Base64.getDecoder();

        /**
         * base64加密
         *
         * @param arr
         * @return
         */
        private static String encodeBase64(byte[] arr) {
            String base64 = null;
            try {
                base64 = ENCODER.encodeToString(arr);
            } catch (Exception e) {
            }
            return base64;
        }

        /**
         * base64解密
         *
         * @param str
         * @return
         */
        public static byte[] decodeBase64(String str) {
            byte[] encodeBase64 = new byte[0];
            try {
                encodeBase64 = DECODER.decode(str);
            } catch (Exception e) {
            }
            return encodeBase64;
        }
    }

    /**
     * 营业执照识别
     * 重要提示代码中所需工具类
     * FileUtil,Base64Util,HttpUtil,GsonUtils请从
     * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
     * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
     * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
     * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
     * 下载
     */
    public static AjaxResult businessLicense(String image) {
        // 请求url
        String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/business_license";
        try {
            // 本地文件路径
            byte[] imgData = FileUtil.readFileByBytes(image);
            String imgStr = com.ruoyi.common.utils.Base64Util.encode(imgData);
            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
            String param = "image=" + imgParam;
            String accessToken = getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK");
            String result = HttpUtils.post(url, accessToken, param);
            /**
             *
             {
             "words_result": {
             "经营范围": {
             "location": {
             "top": 589,
             "left": 381,
             "width": 90,
             "height": 19
             },
             "words": "商务服务业"
             },
             "组成形式": {
             "location": {
             "top": -1,
             "left": -1,
             "width": 0,
             "height": 0
             },
             "words": "无"
             },
             "法人": {
             "location": {
             "top": 537,
             "left": 381,
             "width": 36,
             "height": 19
             },
             "words": "方平"
             },
             "证件编号": {
             "location": {
             "top": 218,
             "left": 302,
             "width": 140,
             "height": 15
             },
             "words": "921MA190538210301"
             },
             "注册资本": {
             "location": {
             "top": 431,
             "left": 1044,
             "width": 152,
             "height": 21
             },
             "words": "200万元"
             },
             "单位名称": {
             "location": {
             "top": 431,
             "left": 384,
             "width": 71,
             "height": 20
             },
             "words": "有限公司"
             },
             "有效期": {
             "location": {
             "top": 536,
             "left": 1044,
             "width": 198,
             "height": 20
             },
             "words": "长期"
             },
             "社会信用代码": {
             "location": {
             "top": 300,
             "left": 241,
             "width": 156,
             "height": 16
             },
             "words": "10440119MA06M85"
             },
             "实收资本": {
             "location": {
             "top": -1,
             "left": -1,
             "width": 0,
             "height": 0
             },
             "words": "无"
             },
             "有效期起始日期": {
             "location": {
             "top": 536,
             "left": 1044,
             "width": 198,
             "height": 20
             },
             "words": "2019年01月01日"
             },
             "核准日期": {
             "location": {
             "top": 884,
             "left": 1188,
             "width": 199,
             "height": 22
             },
             "words": "2019年01月01日"
             },
             "成立日期": {
             "location": {
             "top": 484,
             "left": 1043,
             "width": 126,
             "height": 19
             },
             "words": "2019年01月01日"
             },
             "税务登记号": {
             "location": {
             "top": -1,
             "left": -1,
             "width": 0,
             "height": 0
             },
             "words": "无"
             },
             "地址": {
             "location": {
             "top": 588,
             "left": 1043,
             "width": 55,
             "height": 22
             },
             "words": "广州市"
             },
             "登记机关": {
             "location": {
             "top": 0,
             "left": 0,
             "width": 0,
             "height": 0
             },
             "words": "无"
             },
             "类型": {
             "location": {
             "top": 484,
             "left": 382,
             "width": 258,
             "height": 20
             },
             "words": "有限责任公司(自然人投资或控股)"
             }
             },
             "direction": 0,
             "words_result_num": 16,
             "log_id": "3166723741167575145"
             }
             */
            JSONObject jsonObject = JSONObject.parseObject(result);
            String wordsResult = jsonObject.getString("words_result");
            Map<String, Object> map = new HashMap<>(9);
            if (StringUtils.isNotEmpty(wordsResult)) {
                JSONObject jsonObjectWordsResult = JSON.parseObject(wordsResult);
                String creditCode = JSON.parseObject(jsonObjectWordsResult.getString("社会信用代码")).getString("words");
                String enterpriseName = JSON.parseObject(jsonObjectWordsResult.getString("单位名称")).getString("words");
                String enterpriseType = JSON.parseObject(jsonObjectWordsResult.getString("类型")).getString("words");
                String enterpriseAddress = JSON.parseObject(jsonObjectWordsResult.getString("地址")).getString("words");
                String legalName = JSON.parseObject(jsonObjectWordsResult.getString("法人")).getString("words");
                String registeredCapital = JSON.parseObject(jsonObjectWordsResult.getString("注册资本")).getString("words");
                String establishData = JSON.parseObject(jsonObjectWordsResult.getString("成立日期")).getString("words");
                String businessTerm = JSON.parseObject(jsonObjectWordsResult.getString("有效期")).getString("words");
                String businessScope = JSON.parseObject(jsonObjectWordsResult.getString("经营范围")).getString("words");
                map.put("creditCode", creditCode);
                map.put("enterpriseName", enterpriseName);
                map.put("enterpriseType", enterpriseType);
                map.put("enterpriseAddress", enterpriseAddress);
                map.put("legalName", legalName);
                map.put("registeredCapital", registeredCapital);
                map.put("establishData", establishData);
                map.put("businessTerm", businessTerm);
                map.put("businessScope", businessScope);
            } else {
                return AjaxResult.error("营业执照识别失败,请检查。");
            }
            return AjaxResult.success(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.error();
    }

    /**
     * 人脸识别
     *
     * @throws IOException
     */
    public static AjaxResult sample(SysUserIdcardVo sysUserIdcardVo) {
        String image = sysUserIdcardVo.getImage();
        String idCardNumber = sysUserIdcardVo.getIdCard();
        String name = sysUserIdcardVo.getRealName();
        if (StringUtils.isEmpty(image) || StringUtils.isEmpty(idCardNumber) || StringUtils.isEmpty(name)) {
            return AjaxResult.error("参数不完整");
        }
        // image 可以通过 getFileContentAsBase64("C:\fakepath\1675840208844.png") 方法获取,如果Content-Type是application/x-www-form-urlencoded时,第二个参数传true
        HashMap<String, Object> paramMap = new HashMap<>();
        paramMap.put("access_token", getAccessToken("OmTDmo9hv4wll1ReYiRNJEfz", "vqnio9p7C17nbrkVar0MrHU4KOz2OXOr"));
        paramMap.put("image", getFileContentAsBase64(image, false));
        paramMap.put("image_type", "BASE64");
        paramMap.put("id_card_number", idCardNumber);
        paramMap.put("name", name);
        paramMap.put("spoofing_control", "NORMAL");
        paramMap.put("quality_control", "NORMAL");
        //返回值
        String post = HttpUtil.post("https://aip.baidubce.com/rest/2.0/face/v4/mingjing/verify", paramMap);
        /**
         * {
         *     "log_id": 1370579072568000512,
         *     "result": {
         *         "score": 40.884,
         *         "verify_status": 0
         *     },
         *     "dec_image": "/9j/4AAQSkZJRgABAgAAAQABAAD",
         *     "risk_level": "3",
         *     "risk_tag": [
         *         "若判断为有风险，则会有风险标签json 数组告知风险类型，如：general_inject"
         *     ]
         * }
         */
        JSONObject jsonObject = JSONObject.parseObject(post);
        Map<String, Object> map = new HashMap<>();
        return AjaxResult.success(map);
    }

    /**
     * 获取文件base64编码
     *
     * @param path      文件路径
     * @param urlEncode 如果Content-Type是application/x-www-form-urlencoded时,传true
     * @return base64编码信息，不带文件头
     * @throws IOException IO异常
     */
    static String getFileContentAsBase64(String path, boolean urlEncode) {
        byte[] b = new byte[0];
        try {
            b = Files.readAllBytes(Paths.get(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String base64 = Base64.getEncoder().encodeToString(b);
        if (urlEncode) {
            try {
                base64 = URLEncoder.encode(base64, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return base64;
    }

    /**
     * 获取百度开放平台的AccessToken
     * client_id： 必须参数，应用的API Key；
     * client_secret： 必须参数，应用的Secret Key；不同的功能不同
     *
     * @return
     */
    public static String getAccessToken(String apiKey, String secretKey) {
        String url = "https://aip.baidubce.com/oauth/2.0/token";
        /**
         *grant_type： 必须参数，固定为client_credentials；
         *client_id： 必须参数，应用的API Key；
         *client_secret： 必须参数，应用的Secret Key；
         */
        HashMap<String, Object> paramMap = new HashMap<>(3);
        paramMap.put("grant_type", "client_credentials");
        paramMap.put("client_id", apiKey);
        paramMap.put("client_secret", secretKey);
        String post = cn.hutool.http.HttpUtil.post(url, paramMap);
        JSONObject jsonObject = JSONObject.parseObject(post);
        String accessToken = jsonObject.getString("access_token");
        return accessToken;
    }


    /**
     * 人脸识别阿里云金融级实人认证
     *
     * @throws IOException
     */
    public static AjaxResult ocrSampleAliYun(SysUserIdcardVo sysUserIdcardVo) {

        return AjaxResult.success(initFaceVerify(sysUserIdcardVo));
    }

    /**
     * 阿里云调用人脸识别
     * 每次开始认证前通过本接口获取CertifyId，用来串联认证请求中的各个接口。
     */
    public static Object initFaceVerify(SysUserIdcardVo sysUserIdcardVo) {
        InitFaceVerifyRequest request = new InitFaceVerifyRequest();
        // 请输入场景ID+L。1000009979场景id固定值
        request.setSceneId(1000009979L);
        // 设置商户请求的唯一标识。
        request.setOuterOrderNo(UUID.randomUUID().toString().replaceAll("-", ""));
        // 认证方案。
        request.setProductCode("ID_PRO");
        // 模式。要进行活体检测的类型。取值：
        //LIVENESS（默认）：眨眼动作活体检测。
        //
        //PHOTINUS_LIVENESS：眨眼动作活体+炫彩活体双重检测。
        //
        //MULTI_ACTION：多动作活体检测。当前为眨眼+任意摇头检测。
        request.setModel("PHOTINUS_LIVENESS");
        //不同证件类型，取值均为IDENTITY_CARD
        request.setCertType("IDENTITY_CARD");
        //您的终端用户的真实姓名
        request.setCertName(sysUserIdcardVo.getRealName());
        //您的终端用户的证件号码。
        request.setCertNo(sysUserIdcardVo.getIdCard());
        // MetaInfo环境参数。
        request.setMetaInfo(sysUserIdcardVo.getMetaInfo());
        //业务页面回跳的目标地址。
        String returnUrl = sysUserIdcardVo.getReturnUrl();
        if (StringUtils.isNotEmpty(returnUrl)) {
            //H5的model不一样
            request.setModel("MULTI_ACTION");
            request.setReturnUrl(returnUrl);
        }
        //request.setMobile("130xxxxxxxx");
        //request.setIp("114.xxx.xxx.xxx");
        //request.setUserId("12345xxxx");
        //request.setCallbackUrl("https://www.aliyundoc.com");
        //request.setCallbackToken("xxxxx");
        // 如需开启个人信息加密传输。
        //request.setEncryptType("SM2");
        //request.setCertName("BCRD/7ZkNy7Q*****M1BMBezZe8GaYHrLwyJv558w==");
        //request.setCertNo("BMjsstxK3S4b1YH*****Pet8ECObfxmLN92SLsNg==");

        // 推荐，支持服务路由。
        InitFaceVerifyResponse response = initFaceVerifyAutoRoute(request);

        // 不支持服务自动路由。
        //InitFaceVerifyResponse response = initFaceVerify("cloudauth.cn-shanghai.aliyuncs.com", request);

        response.getBody().getRequestId();
        String certifyId = response.getBody().getResultObject().getCertifyId();

        InitFaceVerifyResponseBody.InitFaceVerifyResponseBodyResultObject resultObject = response.getBody().getResultObject();

        System.out.println(response.getBody().getRequestId());
        System.out.println(response.getBody().getCode());
        System.out.println(response.getBody().getMessage());
        System.out.println(response.getBody().getResultObject() == null ? null
                : response.getBody().getResultObject().getCertifyId());
        return resultObject;
    }

    private static InitFaceVerifyResponse initFaceVerifyAutoRoute(InitFaceVerifyRequest request) {
        // 第一个为主区域Endpoint，第二个为备区域Endpoint。
        List<String> endpoints = Arrays.asList("cloudauth.cn-shanghai.aliyuncs.com", "cloudauth.cn-beijing.aliyuncs.com");
        InitFaceVerifyResponse lastResponse = null;
        for (int i = 0; i < endpoints.size(); i++) {
            try {
                InitFaceVerifyResponse response = initFaceVerify(endpoints.get(i), request);
                lastResponse = response;

                // 服务端错误，切换到下个区域调用。
                if (response != null) {
                    if (500 == response.getStatusCode()) {
                        continue;
                    }
                    if (response.getBody() != null) {
                        if ("500".equals(response.getBody().getCode())) {
                            continue;
                        }
                    }
                }

                // 正常返回
                return lastResponse;
            } catch (Exception e) {
                e.printStackTrace();
                if (i == endpoints.size() - 1) {
                    throw new RuntimeException(e);
                }
            }
        }

        return lastResponse;
    }

    private static InitFaceVerifyResponse initFaceVerify(String endpoint, InitFaceVerifyRequest request)
            throws Exception {
        // 阿里云账号AccessKey拥有所有API的访问权限，建议您使用RAM用户进行API访问或日常运维。
        // 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里，否则可能导致AccessKey泄露，威胁您账号下所有资源的安全。
        // 本示例通过阿里云Credentials工具从环境变量中读取AccessKey，来实现API访问的身份验证。如何配置环境变量，请参见https://help.aliyun.com/document_detail/378657.html。
        Config credentialConfig = new Config();
        credentialConfig.setType("access_key");
        //使用阿里云RAM用户的AK。最小的权限
        credentialConfig.setAccessKeyId("LTAI5tCwkQRjuJYzbohaveEz");
        credentialConfig.setAccessKeySecret("8VW0H8GL7hmm5td8cYxO49FcVLPzOj");
        credentialConfig.setEndpoint(endpoint);
        Client client = new Client(credentialConfig);
        // 设置http代理。
        //config.setHttpProxy("http://xx.xx.xx.xx:xxxx");
        // 设置https代理。
        //config.setHttpsProxy("https://xx.xx.xx.xx:xxxx");


        // 创建RuntimeObject实例并设置运行参数。
        RuntimeOptions runtime = new RuntimeOptions();
        runtime.readTimeout = 10000;
        runtime.connectTimeout = 10000;

        return client.initFaceVerifyWithOptions(request, runtime);
    }


    /**
     * 图片文字识别
     *
     * @param filePath 本地文件路径
     * @return
     */
    public static Map<String, Object> accurateBasic(String filePath) {
        String imgParam = getFileContentAsBase64(filePath, true);
        String param = "image=" + imgParam + "&detect_direction=true";
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        // image 可以通过 getFileContentAsBase64("C:\fakepath\zhizhao.jpg") 方法获取,如果Content-Type是application/x-www-form-urlencoded时,第二个参数传true
        RequestBody body = RequestBody.create(mediaType, param);
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK"))
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Accept", "application/json")
                .build();
        try {
/*            {
                "words_result": [
                    {
                        "words": "http:/10.0.175.74/ahlm/loan/Sv-2024.07.04/jbview.afx.html.print.printer.html?window页码，2024(w9"
                    },
                    {
                        "words": "安徽农金"
                    },
                    {
                        "words": "借据"
                    },
                    {
                        "words": "ARCU"
                    },
                    {
                        "words": "贷款单位：安徽潜山农村商业银行股份有限公司塔畈支行"
                    },
                    {
                        "words": "借款人：潜山和沐物流有限公司"
                    },
                    {
                        "words": "客户编号：200101281091"
                    },
                    {
                        "words": "证件号码：913408243487083682"
                    },
                    {
                        "words": "借据编号：860066291011"
                    },
                    {
                        "words": "借款合同编号：2397591220240003"
                    },
                    {
                        "words": "借款日期：2024年08月09日"
                    },
                    {
                        "words": "借款到期日：2025年08月09日"
                    },
                    {
                        "words": "借款金额（大写）：人民币贰佰万元整"
                    },
                    {
                        "words": "(小写)：￥2,000,000.00"
                    },
                    {
                        "words": "担保方式：保证"
                    },
                    {
                        "words": "借款用途说明：进货"
                    },
                    {
                        "words": "利率种类：年利率"
                    },
                    {
                        "words": "贷款利率：6.09000000%"
                    },
                    {
                        "words": "第一联银行贷款债权凭证"
                    },
                    {
                        "words": "还款方式：按月结息、到期一次性还本法"
                    },
                    {
                        "words": "还款账号：20010128109166600000032"
                    },
                    {
                        "words": "以上款项已转入借款人指定账户"
                    },
                    {
                        "words": "贷款单位（签章"
                    },
                    {
                        "words": "分书·00010X022"
                    },
                    {
                        "words": "借款人（签章或按指印）："
                    },
                    {
                        "words": "负责人："
                    },
                    {
                        "words": "法定代表人（负责人）"
                    },
                    {
                        "words": "孙慧"
                    },
                    {
                        "words": "客户经理"
                    },
                    {
                        "words": "或授权代理人（签章）"
                    },
                    {
                        "words": ".证件号码："
                    },
                    {
                        "words": "经办人："
                    },
                    {
                        "words": "网址：www.ahrcu.com"
                    },
                    {
                        "words": "客服电话：96669"
                    }
                ],
                "words_result_num": 34,
                "direction": 0,
                "log_id": 1824253359437875000
            }*/
            Response response = HTTP_CLIENT.newCall(request).execute();
            String result = response.body().string();
            if (StringUtils.isNotBlank(result)) {
                JSONObject jsonObject = JSONObject.parseObject(result);
                JSONArray wordsResult = jsonObject.getJSONArray("words_result");
                Map<String, Object> bankMap = bank(wordsResult);
                return bankMap;

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从图片识别中提取数据
     *
     * @param wordsResult
     * @return
     */
    public static Map<String, Object> bank(JSONArray wordsResult) {
        Map<String, Object> map = new HashMap<>(2);
        for (int i = 0; i < wordsResult.size(); i++) {
            String o = wordsResult.get(i).toString();
            if (o.contains("\"words\":\"中国银行\"")) {
                for (int p = 0; p < wordsResult.size(); p++) {
                    String b = wordsResult.get(p).toString();
                    if (b.contains("合同金额")) {
                        String[] split = b.split("：");
                        String cny = split[1].replace("CNY", "").replace("\"}", "").replace(",", "");
                        double actuallyAmount = Double.parseDouble(cny) / 10000;
                        map.put("actuallyAmount", actuallyAmount);
                    }
                    if (b.contains("起息日")) {
                        String[] split = b.split("：");
                        String actuallyTime = split[1].replace("\"}", "").replace("/", "-");
                        map.put("actuallyTime", actuallyTime);
                    }
                }
                break;
            } else if (o.contains("\"words\":\"安徽农金\"")) {
                for (int p = 0; p < wordsResult.size(); p++) {
                    String b = wordsResult.get(p).toString();
                    if (b.contains("(小写)")) {
                        String[] split = b.split("：");
                        String cny = split[1].replace("￥", "").replace("\"}", "").replace(",", "");
                        double actuallyAmount = Double.parseDouble(cny) / 10000;
                        map.put("actuallyAmount", actuallyAmount);
                    }
                    if (b.contains("借款日期")) {
                        String[] split = b.split("：");
                        String actuallyTime = split[1].replace("\"}", "").replace("年", "-").replace("月", "-").replace("日", "");
                        map.put("actuallyTime", actuallyTime);
                    }
                }
                break;
            } else if (o.contains("\"words\":\"中国建设银行\"")) {
                //[{"words":"中国建设银行"},{"words":"China Construction Bank"},{"words":"贷款开户放款复核单"},{"words":"交易日期："},{"words":"20240808"},{"words":"交易流水号："},{"words":"102015LN21723106881097611"},{"words":"客户编号："},{"words":"033811000008657356"},{"words":"产品编码："},{"words":"00000082"},{"words":"客户名称："},{"words":"潜山县华达实业有限公司"},{"words":"产品名称："},{"words":"流动资金贷款"},{"words":"币种名称：人民币"},{"words":"币种代码：156"},{"words":"贷款账号："},{"words":"34050368430800000726"},{"words":"放款金额："},{"words":"1000000.00"},{"words":"内部账号："},{"words":"贷转存账号："},{"words":"中建设银行股份有限公司"},{"words":"34050168480800000976"},{"words":"利率(%)：3.750000"},{"words":"贷款放款日期：20240808"},{"words":"到期日期："},{"words":"潜山支行"},{"words":"20250807"},{"words":"业务专用章"},{"words":"授权："},{"words":"复核："},{"words":"经办："},{"words":"53596089vM"}]
                for (int p = 0; p < wordsResult.size(); p++) {
                    String b = wordsResult.get(p).toString();
                    if (b.contains("交易日期")) {
                        String result = wordsResult.get(p + 1).toString();
                        String[] split = result.split(":");
                        String actuallyTime = split[1].replace("}", "").replace("\"", "");
                        map.put("actuallyTime", actuallyTime);
                    }
                    if (b.contains("放款金额")) {
                        String result = wordsResult.get(p + 1).toString();
                        String[] split = result.split(":");
                        //"20240808"}
                        String cny = split[1].replace("}", "").replace("\"", "");
                        double actuallyAmount = Double.parseDouble(cny) / 10000;
                        map.put("actuallyAmount", actuallyAmount);
                    }
                }
                break;
            }
        }
        return map;
    }

/*    public static void main(String[] args) {
        String imgParam = getFileContentAsBase64("D:\\jianhang.jpg", true);
        String param = "image=" + imgParam + "&detect_direction=true";
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        // image 可以通过 getFileContentAsBase64("C:\fakepath\zhizhao.jpg") 方法获取,如果Content-Type是application/x-www-form-urlencoded时,第二个参数传true
        RequestBody body = RequestBody.create(mediaType, param);
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK"))
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Accept", "application/json")
                .build();
        try {
            Response response = HTTP_CLIENT.newCall(request).execute();
            String result = response.body().string();
            if (StringUtils.isNotBlank(result)) {
                JSONObject jsonObject = JSONObject.parseObject(result);
                JSONArray wordsResult = jsonObject.getJSONArray("words_result");
                Map<String, Object> bankMap = bank(wordsResult);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }*/

    /**
     * 图片文字识别
     *
     * @param filePath 本地文件路径
     * @return
     */
    public static Map<String, Object> accurateBasicCj(String filePath) {
        String imgParam = getFileContentAsBase64(filePath, true);
        String param = "image=" + imgParam + "&detect_direction=true";
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        // image 可以通过 getFileContentAsBase64("C:\fakepath\zhizhao.jpg") 方法获取,如果Content-Type是application/x-www-form-urlencoded时,第二个参数传true
        RequestBody body = RequestBody.create(mediaType, param);
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK"))
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Accept", "application/json")
                .build();
        try {
/*            {
                "words_result": [
                    {
                        "words": "http:/10.0.175.74/ahlm/loan/Sv-2024.07.04/jbview.afx.html.print.printer.html?window页码，2024(w9"
                    },
                    {
                        "words": "安徽农金"
                    },
                    {
                        "words": "借据"
                    },
                    {
                        "words": "ARCU"
                    },
                    {
                        "words": "贷款单位：安徽潜山农村商业银行股份有限公司塔畈支行"
                    },
                    {
                        "words": "借款人：潜山和沐物流有限公司"
                    },
                    {
                        "words": "客户编号：200101281091"
                    },
                    {
                        "words": "证件号码：913408243487083682"
                    },
                    {
                        "words": "借据编号：860066291011"
                    },
                    {
                        "words": "借款合同编号：2397591220240003"
                    },
                    {
                        "words": "借款日期：2024年08月09日"
                    },
                    {
                        "words": "借款到期日：2025年08月09日"
                    },
                    {
                        "words": "借款金额（大写）：人民币贰佰万元整"
                    },
                    {
                        "words": "(小写)：￥2,000,000.00"
                    },
                    {
                        "words": "担保方式：保证"
                    },
                    {
                        "words": "借款用途说明：进货"
                    },
                    {
                        "words": "利率种类：年利率"
                    },
                    {
                        "words": "贷款利率：6.09000000%"
                    },
                    {
                        "words": "第一联银行贷款债权凭证"
                    },
                    {
                        "words": "还款方式：按月结息、到期一次性还本法"
                    },
                    {
                        "words": "还款账号：20010128109166600000032"
                    },
                    {
                        "words": "以上款项已转入借款人指定账户"
                    },
                    {
                        "words": "贷款单位（签章"
                    },
                    {
                        "words": "分书·00010X022"
                    },
                    {
                        "words": "借款人（签章或按指印）："
                    },
                    {
                        "words": "负责人："
                    },
                    {
                        "words": "法定代表人（负责人）"
                    },
                    {
                        "words": "孙慧"
                    },
                    {
                        "words": "客户经理"
                    },
                    {
                        "words": "或授权代理人（签章）"
                    },
                    {
                        "words": ".证件号码："
                    },
                    {
                        "words": "经办人："
                    },
                    {
                        "words": "网址：www.ahrcu.com"
                    },
                    {
                        "words": "客服电话：96669"
                    }
                ],
                "words_result_num": 34,
                "direction": 0,
                "log_id": 1824253359437875000
            }*/
            Response response = HTTP_CLIENT.newCall(request).execute();
            String result = response.body().string();
            if (StringUtils.isNotBlank(result)) {
                JSONObject jsonObject = JSONObject.parseObject(result);
                JSONArray wordsResult = jsonObject.getJSONArray("words_result");
                Map<String, Object> bankMap = bankCj(wordsResult);
                return bankMap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * {
     *     "words_result": [
     *         {
     *             "words": "-20230822-287806450001.pdf-Adobe Reader"
     *         },
     *         {
     *             "words": "文档(D)"
     *         },
     *         {
     *             "words": "工具①"
     *         },
     *         {
     *             "words": "窗口(W)"
     *         },
     *         {
     *             "words": "帮助H)"
     *         },
     *         {
     *             "words": "/1"
     *         },
     *         {
     *             "words": "125%"
     *         },
     *         {
     *             "words": "查找"
     *         },
     *         {
     *             "words": "中国银行"
     *         },
     *         {
     *             "words": "贷款放款回单"
     *         },
     *         {
     *             "words": "BANK OF CHINA"
     *         },
     *         {
     *             "words": "客户号：572904279"
     *         },
     *         {
     *             "words": "日期：2023年08月22日"
     *         },
     *         {
     *             "words": "收款人账号：178257778412"
     *         },
     *         {
     *             "words": "贷款账号：181273443198"
     *         },
     *         {
     *             "words": "收款人名称：潜山县永杰竹业有限公司"
     *         },
     *         {
     *             "words": "收款人开户行：中国银行潜山支行"
     *         },
     *         {
     *             "words": "金额：CNY1,000,000.00"
     *         },
     *         {
     *             "words": "人民币壹佰万元整"
     *         },
     *         {
     *             "words": "合同金额：CNY1,000,000.00"
     *         },
     *         {
     *             "words": "合同编号：15003616890"
     *         },
     *         {
     *             "words": "起息日：2023/08/22"
     *         },
     *         {
     *             "words": "到期日：2024/08/22"
     *         },
     *         {
     *             "words": "借款人名称：潜山县永杰竹业有限公司"
     *         },
     *         {
     *             "words": "收款人卡号："
     *         },
     *         {
     *             "words": "附言："
     *         },
     *         {
     *             "words": "中国银行股份有限公司"
     *         },
     *         {
     *             "words": "电子回单专用章"
     *         },
     *         {
     *             "words": "如您已通过银行网点取得相应纸质回单，请注意核对，勿重复记账！"
     *         },
     *         {
     *             "words": "交易机构：08731"
     *         },
     *         {
     *             "words": "交易渠道：柜台"
     *         },
     *         {
     *             "words": "交易流水号：80114160-996"
     *         },
     *         {
     *             "words": "经办："
     *         },
     *         {
     *             "words": "回单编号：2308220801141608"
     *         },
     *         {
     *             "words": "回单验证码：24BN8WT36FM2"
     *         },
     *         {
     *             "words": "打印时间："
     *         },
     *         {
     *             "words": "打印次数："
     *         },
     *         {
     *             "words": "次"
     *         }
     *     ],
     *     "words_result_num": 38,
     *     "direction": 0,
     *     "log_id": 1825789540967617800
     * }
     */

    /**
     * 从图片识别中提取数据
     *
     * @param wordsResult
     * @return
     */
    public static Map<String, Object> bankCj(JSONArray wordsResult) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("dkdw", "");
        map.put("jkr", "");
        map.put("jkje", "");
        map.put("jkytsm", "");
        map.put("hksj", "");
        int hksj = 0;
        String strTime = null;
        String endTime = null;
        for (int i = 0; i < wordsResult.size(); i++) {
            String o = wordsResult.get(i).toString();
            if (o.contains("\"words\":\"中国银行\"")) {
                map.put("zh", "中国银行");
                for (int p = 0; p < wordsResult.size(); p++) {
                    String b = wordsResult.get(p).toString();
                    if (b.contains("收款人开户行")) {
                        String[] split = b.split("：");
                        String cny = split[1];
                        map.put("dkdw", cny);
                    }
                    if (b.contains("借款人名称")) {
                        String[] split = b.split("：");
                        String cny = split[1];
                        map.put("jkr", cny);
                    }
                    if (b.contains("合同金额")) {
                        String[] split = b.split("：");
                        String cny = split[1].replace("CNY", "").replace("\"}", "").replace(",", "");
                        double actuallyAmount = Double.parseDouble(cny) / 10000;
                        map.put("jkje", actuallyAmount);
                    }
                    if (b.contains("起息日")) {
                        String[] split = b.split("：");
                        strTime = split[1].replace("\"}", "").replace("/", "-");
                        map.put("qxr", strTime);
                    }
                    if (b.contains("到期日")) {
                        String[] split = b.split("：");
                        endTime = split[1].replace("\"}", "").replace("/", "-");
                        map.put("dqr", endTime);
                    }
                }
                break;
            } else if (o.contains("\"words\":\"安徽农金\"")) {
                map.put("zh", "安徽农金");
                for (int p = 0; p < wordsResult.size(); p++) {
                    String b = wordsResult.get(p).toString();
                    if (b.contains("贷款单位")) {
                        String[] split = b.split("：");
                        String cny = split[1];
                        map.put("dkdw", cny);
                    }
                    if (b.contains("借款人")) {
                        String[] split = b.split("：");
                        String cny = split[1];
                        map.put("jkr", cny);
                    }
                    if (b.contains("(小写)")) {
                        String[] split = b.split("：");
                        String cny = split[1].replace("￥", "").replace("\"}", "").replace(",", "");
                        double actuallyAmount = Double.parseDouble(cny) / 10000;
                        map.put("jkje", actuallyAmount);
                    }
                    if (b.contains("借款用途说明")) {
                        String[] split = b.split("：");
                        String cny = split[1];
                        map.put("jkytsm", cny);
                    }
                    //计算还款时间
                    if (b.contains("借款日期")) {
                        String[] split = b.split("：");
                        strTime = split[1].replace("\"}", "").replace("年", "-").replace("月", "-").replace("日", "");
                        map.put("qxr", strTime);
                    }
                    if (b.contains("借款到日期")) {
                        String[] split = b.split("：");
                        endTime = split[1].replace("\"}", "").replace("年", "-").replace("月", "-").replace("日", "");
                        map.put("dqr", endTime);
                    }
                }

                break;
            } else if (o.contains("\"words\":\"中国建设银行\"")) {
                //[{"words":"中国建设银行"},{"words":"China Construction Bank"},{"words":"贷款开户放款复核单"},{"words":"交易日期："},{"words":"20240808"},{"words":"交易流水号："},{"words":"102015LN21723106881097611"},{"words":"客户编号："},{"words":"033811000008657356"},{"words":"产品编码："},{"words":"00000082"},{"words":"客户名称："},{"words":"潜山县华达实业有限公司"},{"words":"产品名称："},{"words":"流动资金贷款"},{"words":"币种名称：人民币"},{"words":"币种代码：156"},{"words":"贷款账号："},{"words":"34050368430800000726"},{"words":"放款金额："},{"words":"1000000.00"},{"words":"内部账号："},{"words":"贷转存账号："},{"words":"中建设银行股份有限公司"},{"words":"34050168480800000976"},{"words":"利率(%)：3.750000"},{"words":"贷款放款日期：20240808"},{"words":"到期日期："},{"words":"潜山支行"},{"words":"20250807"},{"words":"业务专用章"},{"words":"授权："},{"words":"复核："},{"words":"经办："},{"words":"53596089vM"}]
                map.put("zh", "中国建设银行");
                map.put("dkdw", "中国建设银行");
                for (int p = 0; p < wordsResult.size(); p++) {
                    String b = wordsResult.get(p).toString();
                    if (b.contains("客户名称")) {
                        String result = wordsResult.get(p + 1).toString();
                        String[] split = result.split(":");
                        String cny = split[1];
                        map.put("jkr", cny);
                    }
                    if (b.contains("放款金额")) {
                        String result = wordsResult.get(p + 1).toString();
                        String[] split = result.split(":");
                        //"20240808"}
                        String cny = split[1].replace("}", "").replace("\"", "");
                        double actuallyAmount = Double.parseDouble(cny) / 10000;
                        map.put("jkje", actuallyAmount);
                    }
                    if (b.contains("产品名称")) {
                        String result = wordsResult.get(p + 1).toString();
                        String[] split = result.split(":");
                        String cny = split[1];
                        map.put("jkytsm", cny);
                    }
                }
                break;
            }
        }
        if (StringUtils.isNotEmpty(strTime) && StringUtils.isNotEmpty(endTime)) {
            hksj = DateUtils.calculateMonths(strTime, endTime);
        }
        if (hksj != 0) {
            map.put("hksj", hksj);
        }
        return map;
    }

    /**
     * 手写文字识别
     */
    /**
     * 重要提示代码中所需工具类
     * FileUtil,Base64Util,HttpUtil,GsonUtils请从
     * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
     * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
     * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
     * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
     * 下载
     */
    public static AjaxResult ocrHandWriting(String filePath) {
        // 请求url
        String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/handwriting";
        try {
            // 本地文件路径
            byte[] imgData = FileUtil.readFileByBytes(filePath);
            String imgStr = Base64Util.encodeBase64(imgData);
            String imgParam = URLEncoder.encode(imgStr, "UTF-8");

            String param = "image=" + imgParam;

            // 注意这里仅为了简化编码每一次请求都去获取access_token，线上环境access_token有过期时间， 客户端可自行缓存，过期后重新获取。
            String accessToken = getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK");

            String result = HttpUtils.post(url, accessToken, param);
            /**
             * {
             *     "log_id": 620759800,
             *     "words_result": [
             *         {
             *             "location": {
             *                 "left": 56,
             *                 "top": 0,
             *                 "width": 21,
             *                 "height": 210
             *             },
             *             "words": "今天"
             *         }
             *     ],
             *     "words_result_num": 1
             * }
             */
            System.out.println(result);
            return AjaxResult.success();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }


    static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
}
