当前位置:网站首页>Custom implementation of Baidu image recognition (instead of aipocr)

Custom implementation of Baidu image recognition (instead of aipocr)

2022-04-23 16:31:00 Spilled off

package com.visy.service;

import com.baidu.aip.util.Base64Util;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.visy.exception.ErrorEnum;
import com.visy.exception.BusinessException;
import com.visy.config.BaiduConfig;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 *  Baidu image recognition custom implementation ( replace AipOcr)
 * @author visy.wang
 * @date 2022/1/19 9:24
 */
@Slf4j
@Service
public class AipOcrClient {
    private static long expireTime = 0L; //token Expiration time stamp 
    private static String accessToken = null; //token value 

    @Autowired
    private BaiduConfig baiduConfig; // Baidu authentication information , Configure your own apiKey and secretKey
    @Autowired
    private RestTemplate restTemplate;

    //Url Management enumeration 
    @Getter
    @AllArgsConstructor
    enum UrlKey {
        ACCESS_TOKEN("https://aip.baidubce.com/oauth/2.0/token", " Certification address "),
        DRIVING_LICENSE("https://aip.baidubce.com/rest/2.0/ocr/v1/driving_license", " Driver's license identification address "),
        VEHICLE_LICENSE("https://aip.baidubce.com/rest/2.0/ocr/v1/vehicle_license", " Driving license identification address ");

        private final String url;
        private final String desc;
    }


    /**
     *  Driver's license identification 
     * @param image  picture ( Binary system )
     * @param options  The other parameters 
     * @return  Recognition result 
     */
    public JSONObject drivingLicense(byte[] image, HashMap<String,String> options){
        options.put("image", Base64Util.encode(image));
        return request(UrlKey.DRIVING_LICENSE, options);
    }

    /**
     *  Driver's license identification 
     * @param imageUrl  Picture address 
     * @param options  The other parameters 
     * @return  Recognition result 
     */
    public JSONObject drivingLicense(String imageUrl, HashMap<String,String> options){
        options.put("url", imageUrl);
        return request(UrlKey.DRIVING_LICENSE, options);
    }

    /**
     *  Identification of driving license 
     * @param image  picture ( Binary system )
     * @param options  The other parameters 
     * @return  Recognition result 
     */
    public JSONObject vehicleLicense(byte[] image, HashMap<String,String> options){
        options.put("image", Base64Util.encode(image));
        return request(UrlKey.VEHICLE_LICENSE, options);
    }

    /**
     *  Identification of driving license 
     * @param imageUrl  Picture address 
     * @param options  The other parameters 
     * @return  Recognition result 
     */
    public JSONObject vehicleLicense(String imageUrl, HashMap<String,String> options){
        options.put("url", imageUrl);
        return request(UrlKey.VEHICLE_LICENSE, options);
    }

    // belt Token Overdue inspection request, Temporarily unnecessary , The expiration time has been calculated and retrieved before expiration 
    private JSONObject requestWithTokenCheck(UrlKey urlKey, Map<String,String> options){
        JSONObject res = request(urlKey, options);
        if(res.has("error_code")){
            int errCode = res.getInt("error_code");
            if(errCode==110 || errCode==111){
                accessToken = null; //Token invalid , Clear and retrieve 
                return request(urlKey, options);
            }
        }
        return res;
    }

    /**
     *  request 
     * @param urlKey url Address enumeration 
     * @param options  The other parameters 
     * @return  Recognition result 
     */
    private JSONObject request(UrlKey urlKey, Map<String,String> options){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        String url = urlKey.getUrl();
        MultiValueMap<String, String> queryStr = getQueryStr(urlKey);
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url).queryParams(queryStr);

        MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
        if(Objects.nonNull(options) && !options.isEmpty()){
            options.forEach(formData::add);
        }

        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(formData, headers);

        ResponseEntity<String> res = restTemplate.postForEntity(uriBuilder.toUriString(), request, String.class);
        if(!HttpStatus.OK.equals(res.getStatusCode())){
            throw buzError(" request was aborted :httpStatus=" + res.getStatusCode());
        }

        String resBody = res.getBody();

        if(StringUtils.isBlank(resBody)){
            throw buzError(" The response body is empty ");
        }

        return new JSONObject(resBody);
    }

    private MultiValueMap<String, String> getQueryStr(UrlKey urlKey){
        MultiValueMap<String, String> queryStr = new LinkedMultiValueMap<>();
        if(UrlKey.ACCESS_TOKEN.equals(urlKey)){
            queryStr.add("grant_type", "client_credentials");
            queryStr.add("client_id", baiduConfig.getApiKey());
            queryStr.add("client_secret", baiduConfig.getSecretKey());
        }else{
            queryStr.add("access_token", getAccessToken()); // Add authentication information 
        }
        return queryStr;
    }

    /**
     *  obtain AccessToken
     * @return AccessToken
     */
    private String getAccessToken(){
        long now = System.currentTimeMillis();

        if(StringUtils.isNotBlank(accessToken) && now<expireTime){
            // There is a cache and it is within the validity period , Use it directly 
            return accessToken;
        }

        try{
            return getAccessToken(now);
        }catch (Exception e){
            throw buzError("AccessToken Acquisition failure :" + e.getMessage());
        }
    }

    private String getAccessToken(long now){
        log.info(" Retrieving AccessToken...");

        JSONObject body = request(UrlKey.ACCESS_TOKEN, null);

        if(body.has("error")){
            throw buzError(body.getString("error_description"));
        }

        int tokenExpires = body.getInt("expires_in"); // The period of validity , Unit second , Default 30 God 
        expireTime = now + (tokenExpires-86400L)*1000L; // advance 1 Days out 
        accessToken = body.getString("access_token"); // cache token
        log.info(" Authentication success , Valid until :{}", new Date(expireTime));

        return accessToken;
    }

    /**
     *  Throw business exception 
     * @param errMsg  error message 
     * @return  Business exceptions 
     */
    private BusinessException buzError(String errMsg){
        //BusinessException:  Custom business exception 
        return new BusinessException(ErrorEnum.BUSINESS_ERR.getCode(), errMsg);
    }
}

package com.visy.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * @author visy.wang
 * @date 2022/1/19 9:28
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "baidu")
public class BaiduConfig {
    private String appId;
    private String apiKey;
    private String secretKey;
}

 

版权声明
本文为[Spilled off]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231403162847.html