1. 程式人生 > >騰訊Ai開放服務接入

騰訊Ai開放服務接入

1.介面呼叫通用形式

如騰訊Ai給出的示例,其中app_id, time_stamp, nonce_str, sign為發起對騰訊Ai各種Api都需要加入到post請求的資料。而key1,key2則根據不同Api會有不同。如下面的OCR通用文字識別Api

這裡寫圖片描述
圖中唯一不同於示例的是把key1,key2換成了image,即待識別圖片的base64編碼資料。
實際上也是如此,對待不同的Api請求,只需要修改key1,key2成對應的鍵值對即可。

2.各欄位資料生成

app_id

app_id為應用標識,到騰訊Ai平臺申請專案就會得到app_id,和app_key。app_key在後續的鑑權生成時會用到。
申請專案獲得金鑰的接入文件

https://ai.qq.com/doc/index.shtml

time_stamp

秒級時間戳
實際上就可以使用系統時間(毫秒)/1000得到需要的值。如:

String time_stamp = System.currentTimeMillis() / 1000 + "";
nonce_str

隨機字串

public static String getRandomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";     
        Random random = new Random();     
        StringBuffer sb = new
StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); }

利用隨機數字去生成即可。

image的base64編碼生成

base64的編碼工具類在網上到處都能找得到,這裡就不貼演算法了,比較長
這個部分的流程主要是將圖片以位元組資料讀入,然後再進行base64編碼

byte[] imageData = FileUtil.readFileByBytes(file);
String img64 = Base64Util.encode(imageData);
sign

先看騰訊給出的說明文件:
這裡寫圖片描述
1.字典升序排序而且還是鍵值對,可以想到使用java中的TreeMap去處理儲存這些資料最為合適
具體簽名部分程式碼如下:

private String generateAppSign() throws UnsupportedEncodingException {
        Set<String> keySet = mParams.keySet();
        StringBuilder sb = new StringBuilder();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = mParams.get(key);
            sb.append("&").append(key).append("=").append(URLEncoder.encode(value, "UTF-8"));
        }
        sb.deleteCharAt(0);
        sb.append("&app_key=").append(TencentAIConstants.APP_KEY_AI);
        String sign = MD5.getMD5(sb.toString());
        return sign;
}

程式碼中的mParams引數就是一個TreeMap物件,儲存著除sign之外的其他鍵值對,利用這些鍵值對計算生成sign欄位。

3.發起請求

發起請求這裡使用okhttp,不使用HttpClient原因是安卓現在不支援使用HttpClient了,使用okhttp使用範圍更廣一點而且也很方便實現。主要程式碼:

MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        Iterator<String> iterator = mParams.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = mParams.get(key);
            builder.addFormDataPart(key, value);
        }
        RequestBody requestBody = builder.build();
        Request request = new Request.Builder().header("Content-Type", "application/x-www-form-urlencoded")
                .url(url)
                .post(requestBody)
                .build();
        OkHttpClient okHttpClient = new OkHttpClient();
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()){
            return ERROR;
        }
        return response.body().string();

4.使用Builder模式寫一個發起請求的類

對於這種部分引數一致,部分引數不同,且邏輯一致的需求使用Builder模式很合適。將上述列出的程式碼使用builder模式寫一個通用的類用於各類請求再合適不過了。程式碼如下:

public class AiRequestBean {

    public static final String ERROR = "error";
    private TreeMap<String, String> mParams;

    private AiRequestBean() {
        mParams = new TreeMap<>();
        //時間戳
        String time_stamp = System.currentTimeMillis() / 1000 + "";
        //隨機字串
        String nonce_str = TencentAIParamsHelper.getRandomString(10);
        //appId
        String app_id = String.valueOf(TencentAIConstants.APP_ID_AI);
        //將通用引數設定進map中
        mParams.put("app_id", app_id);
        mParams.put("nonce_str", nonce_str);
        mParams.put("time_stamp", time_stamp);
    }

    /**
     * TreeMap生成鑑權資訊
     */
    private String generateAppSign() throws UnsupportedEncodingException {
        Set<String> keySet = mParams.keySet();
        StringBuilder sb = new StringBuilder();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = mParams.get(key);
            sb.append("&").append(key).append("=").append(URLEncoder.encode(value, "UTF-8"));
        }
        sb.deleteCharAt(0);
        sb.append("&app_key=").append(TencentAIConstants.APP_KEY_AI);
        String sign = MD5.getMD5(sb.toString());
        return sign;
    }

    //發起請求
    public String request(String url) throws IOException {
        //生成簽名加入到引數列表中
        String sign = generateAppSign();
        mParams.put("sign", sign);
        //使用okhttp發起請求
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        Iterator<String> iterator = mParams.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = mParams.get(key);
            builder.addFormDataPart(key, value);
        }
        RequestBody requestBody = builder.build();
        Request request = new Request.Builder().header("Content-Type", "application/x-www-form-urlencoded")
                .url(url)
                .post(requestBody)
                .build();
        OkHttpClient okHttpClient = new OkHttpClient();
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()){
            return ERROR;
        }
        return response.body().string();
    }

    public static class Builder {
        private AiRequestBean targetBean;

        public Builder() {
            targetBean = new AiRequestBean();
        }

        public AiRequestBean build() {
            return targetBean;
        }

        public Builder addParam(String key, String value) {
            targetBean.mParams.put(key, value);
            return this;
        }
    }
}
    public static final String URL4GENERALOCR  = "https://api.ai.qq.com/fcgi-bin/ocr/ocr_generalocr";
//通用ocr文字識別請求
    public String getGeneralOcrResult(File file) throws Exception {
        byte[] imageData = FileUtil.readFileByBytes(file);
        //準備好圖片base64資料
        String img64 = Base64Util.encode(imageData);
        String jsonResult = new AiRequestBean.Builder().addParam("image", img64).build().request(TencentAIConstants.URL4GENERALOCR);
        return jsonResult;
    }

可以看到還是很方便使用的。