搜索
查看: 2250|回复: 15

[网络] 百度开放平台API调用

[复制链接]

12

主题

680

帖子

3992

积分

荣誉会员

子非魚、安知魚之樂

Rank: 8Rank: 8

积分
3992
发表于 2017-12-27 19:52:54 | 显示全部楼层 |阅读模式
本帖最后由 xauto 于 2017-12-27 21:32 编辑

获得OAuth2.0授权:
目录结构
│      
├─lib
│  │  
│  ├─baidu
│  │      api.aardio
│  │      oauth.aardio

1.oauth.aardio

import crypt.bin;
import crypt.aes;
import fsys.config;
import util.metaProperty;
import web.rest.jsonClient;

namespace baidu;

class oauth {
   
ctor() {
        
this.http = ..web.rest.jsonClient();
        
this.config = ..fsys.config("/config/")
        
this.aes = ..crypt.aes();
    };

    apiKey =
"";
    secretKey =
"";
   
   
//加密
    encrypt = function(s){
        
this.aes.setPassword(this.apiKey);
        
return ..crypt.bin.encodeBase64( this.aes.encrypt(s) )
    }
   
//解密
    decrypt = function(s){
        
this.aes.setPassword(this.apiKey);
        
return this.aes.decrypt( ..crypt.bin.decodeBase64(s) )
    }
   
//获取Token
    getToken = function() {
        
var api = this.http.api("https://aip.baidubce.com/oauth/2.0/");
        
this.http.extraUrlParameters = {
            grant_type =
"client_credentials";
            client_id =
this.apiKey;
            client_secret =
this.secretKey;
        }
        
var json,err = api.token();
        
if(!json) error(err)
        
this.config.oauth.mixin(
           token =
this.encrypt(json.access_token);
           expires = ..time.now().addday(29);
//有效期30天,提前一天
        );
    }
   
//是否过期
    isExpires = function(){
        
var t = ..time.now()
        
if(!this.config.oauth.expires) this.getToken();
        
var e = this.config.oauth.expires;
        
if(e.diffday(t)>0) return false;
        
else return true;  
    }
   
    @_metaProperty;
}

oauth._metaProperty = ..util.metaProperty(

    token = {
        _get =
function() {
            
var t = owner.config.oauth.token;
            
if(!t || owner.isExpires()) owner.getToken()
            
return owner.decrypt(owner.config.oauth.token);
        }
    }
)
//百度AIP开放平台OAuth2.0授权
//http://ai.baidu.com/docs#/Auth/top

点评

真棒: 5.0
真棒: 5
代码漂亮!  发表于 2017-12-27 19:55

评分

参与人数 1银币 +30 收起 理由
cf702@vip.qq.co + 30 很给力!

查看全部评分

回复

使用道具 举报

171

主题

2506

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13764
发表于 2017-12-27 21:55:48 | 显示全部楼层
非常感谢xauto分享的代码,代码写的很好。
这里我谈一下我的看法,换一个思路实现一下,意见仅供参考。

我个人认为,写库的时候,可以考虑有一些功能不去实现,库的功能职责专一化,
例如把token保存到配置文件这种事,可以留给下一层的代码去处理。而且一个token的失效时间是一个月,似乎不需要去保存一个月,这样好像也不安全。

但模块化这个东西,还要拿捏到合适的位置,
例如oauth有没有必要单独拿出来呢?!我觉得可以不拿出来。
再例如,api有必有必要封装一个对象呢?!我觉得从HTTP客户端这个层次来说,不用去单独实现一个模块,也就是说,可以不用一个API创建一个HTTP客户端。

另外,我看了一下文档,请求的时候他要用application/x-www-form-urlencode,
那么这里可以考虑用 web.rest.jsonLiteClient 就行了,请求的时候不用JSON,只有返回才是JSON,
在这个基础上我写了一个库:
import web.rest.jsonLiteClient;

namespace baidu;

class client{
   
ctor(apiKey,secretKey){
        
        
this = ..web.rest.jsonLiteClient()
        
this.apiKey = apiKey;
        
this.secretKey = secretKey;

        
this.oauthApi = this.api("https://aip.baidubce.com/oauth/2.0/","GET");
    };
    auth =
function(){
        
var result,err = this.oauthApi.token({
            grant_type =
"client_credentials";
            client_id =
this.apiKey;
            client_secret =  
this.secretKey;
        });
        
if(!result[["access_token"]]) return null,"认证失败";
        
        
this.oauthInfo = result;
        
this.extraUrlParameters = {
            access_token = result.access_token;
        }
        
return this.oauthInfo;
    }
   
}

虽然库的代码变少了,但调用起来并不会更复杂,调用示例如下:

//百度OCR文字识别
import console
import baidu.client;

//创建百度客户端
var http = baidu.client(
   
"tTSWGGGaLXz48TWAN9g1qgGk",//你自己的API Key
    "ha10bCHkw2UssZDrbo09snvXw2x4SZeb" //你自己的Secret Key
)

//oauth认证
if(! http.auth() ){
   
error("认证失败")
}
   
//OCR识别接口
var ocr = http.api("https://aip.baidubce.com/rest/2.0/ocr/v1/");

//调用ocr
var result = ocr.general_basic(
    url =
"http://img.vim-cn.com/68/79d6ea4fad08286b3260170664b4bba2cbfa6c.bmp";  
)

console.dumpJson(result);
console.pause(
true);
  
我为什么要这么写呢?!
因为这样 baidu.client这个对象,直接继承自 web.rest.jsonLiteClient
这样用法就跟原来一样,不用学新东西


上面的KEY就给大家测试吧。
回复

使用道具 举报

171

主题

2506

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13764
发表于 2017-12-30 04:38:14 | 显示全部楼层
看了一下百度的文档,基本都是image字段才要base64,
小改了一下库,image字段的值可以直接写图像数据,或者本地文件路径,或者写一个网址,其他事件自动处理。

上传到扩展库了,例子:
import win.ui;
/*DSG{{*/
var winform = win.form(text="百度API测试";right=747;bottom=463;acceptfiles=1)
winform.add(
button={cls=
"button";text="识别";left=596;top=411;right=731;bottom=449;dr=1;dt=1;z=3};
edit={cls=
"edit";left=16;top=18;right=731;bottom=379;db=1;dl=1;dr=1;dt=1;edge=1;multiline=1;vscroll=1;z=1};
editUrl={cls=
"edit";text="http://bbs.aardio.com/data/attachment/forum/201712/29/213348g7wpsalpnn8gdnnp.png.thumb.jpg";left=16;top=415;right=591;bottom=447;align="right";dl=1;dr=1;dt=1;edge=1;z=2};
static={cls=
"static";text="请输入图像文件路径、或者网址:";left=21;top=392;right=234;bottom=407;dr=1;dt=1;transparent=1;z=4}
)
/*}}*/

import web.json;  
winform.button.oncommand =
function(id,event){
   
    winform.button.disabled =
true;
   
    thread.invoke(
        
function(winform){
            
            
import baidu.client;
            
var http =  baidu.client();//创建百度客户端
            
            
//oauth认证
            if(! http.setAuth(
               
//可以用一个参数直接写access_token,或者写一个可以获取access_token的网址
                "tTSWGGGaLXz48TWAN9g1qgGk",//你自己的API Key
                "ha10bCHkw2UssZDrbo09snvXw2x4SZeb" //你自己的Secret Key   
            ) ){
                winform.edit.print(
"oauth认证证失败")
            }
            
            
else{
               
               
//OCR识别接口
                var ocr = http.api("https://aip.baidubce.com/rest/2.0/ocr/v1/");
                    
               
//调用ocr
                var result = ocr.general_basic(
                    
//这里可以写直接写本地图片路径、或者加载后的图像数据、也可以写URL
                    image = winform.editUrl.text;
                )
               
               
if(result) winform.edit.print(result);
               
else {
                    winform.edit.print( http.lastResponse() );
                }
            }
            
            winform.button.disabled =
false;   
        },winform
    )
}

winform.onDropFiles =
function(files){
    winform.editUrl.text = files[1];
}

winform.show()
win.loopMessage();

可以直接写access_token

import console

//创建百度客户端
import baidu.client;
var http =  baidu.client();

//oauth认证
http.setAuth(
     
"这里可以直接写一个access_token,神奇的是这个key可以乱改:
     24.2bdb36f39ef94eeaa5be42190691d64e.2592000.1517167908.282335-10594088"

)

//OCR识别接口
var ocr = http.api("https://aip.baidubce.com/rest/2.0/ocr/v1/");
     
//调用ocr
var result = ocr.general_basic(
   
//这里可以写直接写本地图片路径、或者加载后的图像数据、也可以写URL
    image = "http://bbs.aardio.com/data/attachment/forum/201712/29/213348g7wpsalpnn8gdnnp.png.thumb.jpg";
)
     

console.dumpJson(result);
console.pause(
true);  

也可以干脆只写一个可以获取access_token的网址,Secret Key  这些其实是没必要写到客户端软件里的,例如:
import console

import baidu.client;
var http =  baidu.client();
http.setAuth(
"http://update.aau.cn/v10/test/test-baidu.aardio")
   
//OCR识别接口
var ocr = http.api("https://aip.baidubce.com/rest/2.0/ocr/v1/");
var result = ocr.general_basic(
    image =
"http://bbs.aardio.com/data/attachment/forum/201712/29/213348g7wpsalpnn8gdnnp.png.thumb.jpg";
)

console.dumpJson(result);
console.pause(
true);  


代码可以越改越简单。


回复

使用道具 举报

12

主题

680

帖子

3992

积分

荣誉会员

子非魚、安知魚之樂

Rank: 8Rank: 8

积分
3992
 楼主| 发表于 2017-12-27 19:53:40 | 显示全部楼层
2 api.aardio

import web.rest.jsonClient;

namespace baidu;

class api {
   
ctor(url, token) {
        
this.url = url;
        
this.token = token;
        
this.http = ..web.rest.jsonClient();
    };

    request =
function(method, params) {
        
var api = this.http.api(this.url);
        
this.http.extraUrlParameters = ..table.mixin(params, {
            access_token =
this.token;
        })
        
return api[method]();
    }

    @ {
        _get =
function(method) {
            
return function(params) {
               
return this.request(method, params)
            }
        }
    }
}

//百度API服务
//http://ai.baidu.com/docs#/Begin/top


回复

使用道具 举报

12

主题

680

帖子

3992

积分

荣誉会员

子非魚、安知魚之樂

Rank: 8Rank: 8

积分
3992
 楼主| 发表于 2017-12-27 19:56:37 | 显示全部楼层
范例:

//百度OCR文字识别

import baidu.api;
import baidu.oauth;

import console;
var oauth = baidu.oauth();
oauth.apiKey =
"API_Key" //你自己的API Key
oauth.secretKey = "Secret_Key" //你自己的Secret Key


//OCR识别
var ocr = baidu.api("https://aip.baidubce.com/rest/2.0/ocr/v1/", oauth.token);

var json = ocr.general_basic(
   
//当image字段存在时url字段失效
    //image = crypt.bin.encodeBase64(string.load("\res\test.png"));
    url = "http://img.vim-cn.com/68/79d6ea4fad08286b3260170664b4bba2cbfa6c.bmp"
)

console.dumpJson(json)
console.pause(
true);

//百度OCR识别
//http://ai.baidu.com/docs#/OCR-API/top
回复

使用道具 举报

171

主题

2506

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13764
发表于 2017-12-27 20:18:47 | 显示全部楼层
这里这样写一下可能好点:
var json,err = api.token();
if(!json) error(err) ;
不然写错了key,多复制个空格什么的,可以方便一点

回复

使用道具 举报

12

主题

680

帖子

3992

积分

荣誉会员

子非魚、安知魚之樂

Rank: 8Rank: 8

积分
3992
 楼主| 发表于 2017-12-27 21:27:29 | 显示全部楼层
Jacen.He 发表于 2017-12-27 20:18
这里这样写一下可能好点:不然写错了key,多复制个空格什么的,可以方便一点

嗯  重构的时候忘记判断了
回复

使用道具 举报

171

主题

2506

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13764
发表于 2017-12-27 22:04:24 | 显示全部楼层
开始我看了xauto的代码,误以为百度是要在POST下面以GET方式传参数,所以写了以下代码
this = ..web.rest.jsonLiteClient()
this.stringifyRequestParameters = function(params){
   
this.lastRequestUrl = ..inet.url.appendExtraInfo(
        
this.lastRequestUrl, ..inet.url.stringifyParameters(params)
    );
   
return null;
}
后来看了他的文档才知道直接用 web.rest.jsonLiteClient 就可以了

回复

使用道具 举报

12

主题

82

帖子

746

积分

培训班

积分
746
QQ
发表于 2017-12-27 22:04:36 | 显示全部楼层
Jacen.He 发表于 2017-12-27 21:55
非常感谢xauto分享的代码,代码写的很好。
这里我谈一下我的看法,换一个思路实现一下,意见仅供参考。

...

威武霸气简练。正好对照学习!辛苦了!
回复

使用道具 举报

12

主题

680

帖子

3992

积分

荣誉会员

子非魚、安知魚之樂

Rank: 8Rank: 8

积分
3992
 楼主| 发表于 2017-12-27 22:39:15 | 显示全部楼层
Jacen.He 发表于 2017-12-27 21:55
非常感谢xauto分享的代码,代码写的很好。
这里我谈一下我的看法,换一个思路实现一下,意见仅供参考。

...

学习了,一直忽略了还有一个web.rest.jsonLiteClient
另外获取oauth(文档推荐使用POST)这里直接用默认Method应该就可以了
this.oauthApi = this.api("https://aip.baidubce.com/oauth/2.0/");
回复

使用道具 举报

1

主题

62

帖子

1457

积分

新手入门

积分
1457
发表于 2017-12-28 11:02:07 | 显示全部楼层
Jacen.He 发表于 2017-12-27 21:55
非常感谢xauto分享的代码,代码写的很好。
这里我谈一下我的看法,换一个思路实现一下,意见仅供参考。

...

发现个问题,上面返回的信息中,log_id的值是一个很大的数,经过json解析转换成aar对象后,变成用科学记数法来记录了,那么,假如调用一个接口是需要使用到另外一些接口的返回的信息,有可能会失败
回复

使用道具 举报

171

主题

2506

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13764
发表于 2017-12-28 12:33:46 | 显示全部楼层
松江 发表于 2017-12-28 11:02
发现个问题,上面返回的信息中,log_id的值是一个很大的数,经过json解析转换成aar对象后,变成用科学记数法 ...

他的文档里说这是一个uint64类型数,json是源于js的,js中并不能表示uint64,在json里这样写很多语言都会转为科学计数法,因为json没办法描述数值的类型。

我看了一下,他的 log_id的说明是“唯一的log id,用于问题定位”,似乎只是用来调试的并没有什么用处,你说的假如.........什么什么,根据是什么呢?

针对这个问题我改了一下:
var n,l = tonumber( nextStr,10 );
if(n!==null){
   
if( (n===0) && (nextStr[2] =='x'#) ){
        n,l =
tonumber( nextStr,16 );
        
if( n === null ){
            
error("json格式错误 - 16进制数值"+sub(str,pos),3)
        }
    }
   
elseif(l>14) {
        
var s = sub(nextStr,1,l);
        
if( !find(s,"\.") )
            n = ..math.size64(s);
    }
   
   
return n,pos+l;
}
但是这种问题,应不应该改是个问题。

原来就是一句tonumber() ,想法越来越多,有的人要写16进制,有的人还要写uint64,判断语句就会越加越多。但这些都是不符合JSON规范的写法。

JSON5里就有很多这种神奇的想法

回复

使用道具 举报

34

主题

163

帖子

943

积分

荣誉会员

吃白菜的鸟

Rank: 8Rank: 8

积分
943
发表于 2017-12-29 21:35:58 | 显示全部楼层
本帖最后由 popdes 于 2017-12-29 22:04 编辑

用百度的识别车牌的测试了下, 效果不错哦...
就是要一直联网才能识别...
1514540087744876.png

  1. //车牌识别接口
  2.     var ocr = http.api("https://aip.baidubce.com/rest/2.0/ocr/v1/");
  3.      
  4.     //调用ocr
  5.     var result = ocr.license_plate(
  6.         //加载本地图片
  7.         image = inet.url.encodeUri(string.base64.encode(string.load(filePath)));
  8.     )
  9.      //输出json到编辑框
  10.     mainForm.edit2.print(result ,'\r\n' )
复制代码


要是一张图片里有好多个车牌,那么增加个参数即可
  1. //调用ocr
  2.     var result = ocr.license_plate({
  3.         image = inet.url.encodeUri(string.base64.encode(string.load(filePath)));
  4.         multi_detect = true;
  5.         }
  6.     )
复制代码
!
回复

使用道具 举报

12

主题

680

帖子

3992

积分

荣誉会员

子非魚、安知魚之樂

Rank: 8Rank: 8

积分
3992
 楼主| 发表于 2017-12-29 22:04:39 | 显示全部楼层
popdes 发表于 2017-12-29 21:35
用百度的识别车牌的测试了下, 效果不错哦...
就是要一直联网才能识别...

//这里不需要url编码,因为web.rest.jsonLiteClient 默认已经编码过了
//string.base64.encode() 建议使用速度更快的 crypt.bin.encodeBase64()
image = inet.url.encodeUri(string.base64.encode(string.load(filePath)));

回复

使用道具 举报

34

主题

163

帖子

943

积分

荣誉会员

吃白菜的鸟

Rank: 8Rank: 8

积分
943
发表于 2017-12-29 22:11:34 | 显示全部楼层
xauto 发表于 2017-12-29 22:04
//这里不需要url编码,因为web.rest.jsonLiteClient 默认已经编码过了
//string.base64.encode() 建议使 ...

改成这样了
image = crypt.bin.encodeBase64(string.load(filePath));
简洁不少,哈,谢谢
当时测试不加url编码没通过,所以加了, 现在重新测, 发现又没问题了.⊙﹏⊙b汗
!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

手机版|未经许可严禁引用或转载本站文章|站长邮箱|aardio.com|aardio官方社区 ( 皖ICP备09012014号 )

GMT+8, 2018-7-19 19:20 , Processed in 0.078125 second(s), 26 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表