相关网址:https://ai.qq.com/doc/auth.shtml
如腾讯Ai给出的示例,其中app_id, time_stamp, nonce_str, sign为发起对腾讯Ai各种Api都需要加入到post请求的数据。而key1,key2则根据不同Api会有不同。如下面的OCR通用文字识别Api
图中唯一不同于示例的是把key1,key2换成了image,即待识别图片的base64编码数据。
实际上也是如此,对待不同的Api请求,只需要修改key1,key2成对应的键值对即可。
app_id为应用标识,到腾讯Ai平台申请项目就会得到app_id,和app_key。app_key在后续的鉴权生成时会用到。
申请项目获得密钥的接入文档https://ai.qq.com/doc/index.shtml
秒级时间戳
实际上就可以使用系统时间(毫秒)/1000得到需要的值。如:
String time_stamp = System.currentTimeMillis() / 1000 + "";
随机字符串
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();
}
利用随机数字去生成即可。
base64的编码工具类在网上到处都能找得到,这里就不贴算法了,比较长
这个部分的流程主要是将图片以字节数据读入,然后再进行base64编码
byte[] imageData = FileUtil.readFileByBytes(file);
String img64 = Base64Util.encode(imageData);
先看腾讯给出的说明文档:
1.字典升序排序而且还是键值对,可以想到使用java中的TreeMap去处理存储这些数据最为合适
具体签名部分代码如下:
private String generateAppSign() throws UnsupportedEncodingException {
Set keySet = mParams.keySet();
StringBuilder sb = new StringBuilder();
Iterator 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字段。
发起请求这里使用okhttp,不使用HttpClient原因是安卓现在不支持使用HttpClient了,使用okhttp使用范围更广一点而且也很方便实现。主要代码:
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
Iterator 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();
对于这种部分参数一致,部分参数不同,且逻辑一致的需求使用Builder模式很合适。将上述列出的代码使用builder模式写一个通用的类用于各类请求再合适不过了。代码如下:
public class AiRequestBean {
public static final String ERROR = "error";
private TreeMap 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 keySet = mParams.keySet();
StringBuilder sb = new StringBuilder();
Iterator 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 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;
}
}
}
使用方法也很简单,比如以通用ocr为例,通用ocr文字识别中不同的参数为image,对应的Api为”https://api.ai.qq.com/fcgi-bin/ocr/ocr_generalocr”
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;
}
可以看到还是很方便使用的。
Demo代码链接:http://download.csdn.net/download/breeze048/10267182