搜索
查看: 36679|回复: 11

[web] 使用 web.rest 实现 rest-rpc

  [复制链接]

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
发表于 2013-11-17 00:13:13 | 显示全部楼层 |阅读模式
用web.rest可以把任何普通的HTTP API转换为aardio中的函数调用(我们称之为 rest-rpc )标准库中用于支持 rest-rpc 的库:
web.rest.client 请求参数使用urlencode编码,服务器返回文本数据。
web.rest.xmlClient 请求参数使用urlencode编码,服务器返回xml格式数据
web.rest.jsonLiteClient 请求参数使用urlencode编码,服务器返回JSON格式数据。
web.rest.jsonClient 请求参数与服务器返回数据都使用JSON格式

除了与服务器交互的数据格式不同以外, 这几个库的接口用法完全一样,可以看看这几个库的源码实际上他们都是调用 web.rest.client 这一个库。

先看一个最简单的例子:
import console;
import web.rest.jsonClient;

var http = web.rest.jsonClient();
var jsonstore = http.api("https://www.jsonstore.io/e5fd2bdf0e6b3ba3fe4aa61eebd11740cf2fe10e7fad1b5d2fb77c876498baf5");

//增
var result = jsonstore.user[1].post(
    name =
"jon.snow";
    age = 31;
)

//改
var result = jsonstore.user[1].age.put(32);

//查
var result = jsonstore.user[1].get();

//删
var result = jsonstore.user[1].delete();
console.dump(result);

console.pause()


下面讲解具体用法

一、使用 web.rest 执行基本的HTTP请求

web.rest下面的支持库最简单的用法就是作为一个HTTP客户端使用,该客户端对象简化了get,post,put,patch,delete等常用的HTTP请求操作,并提供编码请求数据、解码返回数据的功能,下面是一个最简单的示例:
import console;
import web.rest.jsonLiteClient;

var restClient = web.rest.jsonLiteClient();  
var jsonData = restClient.post("http://eu.httpbin.org/post",{
    用户名 =
"用户名";
    密码 =
"密码";
} )

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

从上面的示例可以看出,我们上传参数的是aardio中的对象,返回的数据也被自动解码为aardio对象,虽然HTTP传输使用的是JSON数据,但使用时不需要去管JSON的编解码等一系列的操作。

二、使用 web.rest 将 Web API 转换为 aardio函数

web.rest 不仅仅可以用来做上面这些简单的HTTP请求、以及编解码的操作,他还可以将基本符合REST风格的Web API转换为aardio中的函数对象(rest-rpc),这非常有意思,REST本身缺乏WebService那样的WSDL接口描述服务,但是aardio设计了一种简单可行的声明语法,可以非常方便的把混乱的Web API转换为统一的aardio函数。

首先我们看一下REST API的URL一般会是这种格式 http://主机/资源目录名/资源目录名/资源名
aardio的web.rest库模块中的客户端对象提供一个api 函数用于声明一个API接口,api 函数的定义如下
var restApi = restClient.api("接口URL描述","默认HTTP请求动词")

其中接口URL描述可以直接指定一个web api的网址,在该网址中还可以使用变量,变量放在花括号中,例如:
http://主机/{变量名}/资源目录名/资源名 aardio并不关心变量名的内容是什么,只关心它们出现的前后顺序,当调远程函数时会使用对象名字、函数名字替换接口URL中的变量生成新的请求URL。

下面是一个简单的示例:

import console;
import web.rest.jsonClient;

// 创建REST客户端
var restClient = web.rest.jsonClient();

//声明一个rest-rpc接口,第一个参数指定URL描述
var restApi = restClient.api("http://eu.httpbin.org/api/{program}/{lang}")

/*
下面调用接口函数,
在请求时下面代码中的接口名"language"替换接口URL描述中的变量{program}
接口名"aardio"则替换接口URL描述中的变量{lang}
最后生成的请求URL为 http://eu.httpbin.org/api/language/aardio
*/

var result = restApi.language.aardio()

console.log(
"请求的URL",restClient.lastRequestUrl )
restClient.lastResponse();
//输出服务端最后返回的数据

console.pause();

接口URL中连接的变量名还可以合并为{...}
例如  "http://eu.httpbin.org/api/{program}/{lang}" 可以简写为 "http://eu.httpbin.org/api/{...}"
当 {...} 出现在尾部时还可以直接省略,例如 "http://eu.httpbin.org/api/"


注意head,get,post,put,patch,delete等默认的HTTP请求操作作为函数名时不会被添加到生成的URL中。
这些默认的HTTP方法名在 web.rest.
client._defaultMethod 中指定,例如使用 restApi.language.get() 显示的指定HTTP请求动词为“GET”。如果不指定HTTP请求动词,则使用调用 restClient.api("接口URL描述","默认HTTP请求动词") 函数时第二个参数指定的HTTP请求动词,不指定该参数时默认为"POST"

HTTP规定了九种动词(Verbs)用于指定请求方法:GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS,
而在 rest-rpc 中用到的有五种 GET,POST,PUT,DELETE,PATCH,他们的用途如下:
GET:用于获取数据
POST:  用于创建数据
PUT: 用于替换数据、也可用于更新数据
DELETE: 用于删除数据
PATCH:用于更新数据

三、使用 web.rest 上传下载文件

如量一个REST API在请求时需要上传、下载文件,那么所有调用规则如前不变,
你仅仅需要做的时,在调用API以前指定接受、或发送文件的回调函数以获取上传、下载的进度,

上传文件示例:
restClient.sendFile( "上传文件路径"
    ,
function(str,sendSize,contentLength){
        ..io.print(
"正在上传",sendSize,contentLength);
    }
);

//在后面再简单的调用API就可以了,例如
restApi.upload()

下载文件示例:
restClient.receiveFile( "上传文件路径"
    ,
function(str,receiveSize,contentLength){
        ..io.print(
"正在下载",receiveSize,contentLength);
    }
);

//在后面再简单的调用API就可以了,例如
restApi.download()

web.rest 也可以支持 multipart/form-data 编码上传文件,示例:
import console;
import web.rest.client;

var http = web.rest.client();
http.sendMultipartForm( {
        file =
"@d:\文件路径";
        username =
"测试";
    },
function(str,sendSize,contentLength){
        console.log(
"正在上传",sendSize,contentLength);
    }
);
var str =http.post("http://eu.httpbin.org/post")
console.pause(,str)
  







回复

使用道具 举报

30

主题

693

帖子

4168

积分

超级版主

Rank: 8Rank: 8

积分
4168
发表于 2015-11-28 12:12:59 | 显示全部楼层

四、web.rest客户端对象的错误处理

web.rest客户端对象的错误处理与inet.http相同:
请求成功返回服务器数据,失败返回空值,错误信息,错误代码等。
下面具体用代码演示详细的错误处理代码( 注意下面为了演示所有的细节,代码写的比较长,实际开发中不必要写的这么细)
import console;
import web.rest.jsonLiteClient;

var restClient = web.rest.jsonLiteClient();  

/*
web.rest客户端对象所以执行HTTP请求的函数遵守以下规则:
如果成功,则第一个返回值jsonData为服务端返回数据解码并创建的aardio对象。
在HTTP请求遇到错误时,第一个返回值jsonData为空,第二个返回值errMsg为错误信息,返回值errCode为错误代码
一般我们可以省略errMsg,errCode这两个返回值不用写,直接判断返回值是否为空即可。  
*/

var jsonData,errMsg,errCode = restClient.post("http://eu.httpbin.org/post",{
    用户名 =
"用户名";
    密码 =
"密码";
} )

//jsonData非空为请求成功
if( jsonData ){
    console.dumpJson(jsonData);
}
else {
   
/*
    出错了,如果restClient.lastStatusCode非空则说明服务端返回了HTTP状态代码
    */

   
if(  restClient.lastStatusCode ){
        console.log( restClient.lastStatusMessage() )
//查看该状态码的说明
        restClient.lastResponse() //输出服务端最后返回的信息
    }
   
else {
        
//这通常是没有成功发送请求,在请求到达服务器以前就出错了
        console.log("HTTP请求遇到错误,WinInet错误代码:",errCode )
        console.log(
"关于WinInet错误代码的详细说明:http://support.microsoft.com/kb/193625 ")
    }
   
}
console.pause();
当然上面的代码一般在调试故障时才需要,一般没必要把错误处理写的这么细,上面的代码也可以简化如下:
import web.rest.jsonLiteClient;
var restClient = web.rest.jsonLiteClient();   

var 鸭子 = restClient.post("http://eu.httpbin.org/post",{
    用户名 =
"用户名";
    密码 =
"密码";
} )
  
if( 鸭子[["翅膀"]] ){ //这句相当于 if( 鸭子 and 鸭子.翅膀 )
    io.print("不管服务器给我的是什么鸭子,总之有翅膀的都是好鸭子")
}
else {
   
//我的网络错误处理模块.错误统一分析("怎么回事没翅膀还能叫鸭子吗?",restClient.lastStatusCode)
    return null,"网络错误"
}
   



回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2013-11-17 00:25:27 | 显示全部楼层

五、关于 rest-rpc

实际上REST本身是试图对URL进行规范,但现在流行的所谓REST API多数只剩下了“URL"而扔掉了“规范”,实际上REST里其他东西没什么用,最有用的就是“URL”这个词,把URL本身当接口来设计简洁、轻快、实用,这才是REST API广泛流行的真正原因,很多人解释不清为什么很多声称REST API的API压根就不符合REST的原则,其实很简单,REST这个词被过度神化了,所以不要去纠结哪个API符不符合REST原则,基本上,你没有任何必要去学习这个东西(因为REST里真正有用的只是一种解决问题的态度,而条款都没有用)。

实际上使用web.rest可以把任何普通的HTTP API转换为aardio中的函数调用(我们称之为 rest-rpc ),但遵守下面的规则可以做的更好。

1、HTTP服务端提供的接口URL要能使用以下的URL描述规则:

     URL中的资源名应当能使用{模板变量}代替、{模板变量}的先后关系应当对应资源名的出现顺序。
     {模板变量}包含在花括号里 - 可以使用多个数字或字母,数值的大小并不重要,URL描述仅关心资源出现的先后关系。
     可以使用 {...} 表示不定个数的模板变量。

     http://主机/资源分类/资源目录/资源名/资源ID
     使用URL描述语法转换结果就是这样: http://主机/{res}/{category}/{name/{id}
     也可以使用 http://主机/{res}/{...} 表示。  如果 {...} 出现在最后则可以省略

     HTTP://主机/资源分类?资源目录=目录名&资源名=资源名&资源ID=资源ID
     使用URL描述语法转换以后: HTTP://主机/{res}?资源目录={category}&资源名={name}&资源ID={id}

     可以看到资源名是不是写到参数里都能清晰的展现资源定位,要注意 Web API 并不是浏览器,URL并不会出现在浏览器的地址栏,设计一个友好的API URL重要的是编程语言里能不能更好的理解并自动分析转换。 例如aardio中的 web.rest.client 就按照这种URL描述语法自动的将URL描述转换为aardio中的函数对象。

2、URL不应当包含以下HTTP指令动词:
GET: 表示获取资源
POST: 表示新增数据
PUT: 表示替换数据
DELETE: 表示删除数据
PATCH: 表示更新数据

可选在URL的最后一层目录添加扩展的操作动词,例如:
http://host/group/user/id/ 使用get读取用户信息
http://host/group/user/id/password/change 使用扩展的change方法修改用户密码

如果按这种规则实现服务端的API,那么在aardio里用 web.rest.client 调用起来就很方便,示例:
import web.rest.jsonClient;
var client = web.rest.jsonClient()
var api = client.api("http://host/{group}/{..}")

// GET方法读取用户信息
var userInfo = api.xgroup.user[userId].get()

// 使用扩展的change方法修改密码
api.xgroup.user[userId].passord.change(
    pwd =
"旧密码";
    newPwd =
"新密码";
)

为什么不直接在每一个请求里写具体的URL呢?要考虑到实现一个API的扩展库,API服务端的地址可能发生变更,使用上面的方法就可以简单的维护一个声明URL参数即可。

3、rest-rpc 的URL中不应出现文件后缀名.

     例如: http://host/x/y.aardio 应当在服务器上移动到 http://host/x/y/main.aardio,然后提供给客户端的API应隐藏默认的文档名,即 http://host/x/y/ 这样的好处是服务端变更实现会非常方便。

4、rest-rpc 的URL中不应出现IP地址,即使是测试期间,也应尽可能的使用域名替代IP地址。


回复

使用道具 举报

30

主题

693

帖子

4168

积分

超级版主

Rank: 8Rank: 8

积分
4168
发表于 2016-4-16 23:34:54 | 显示全部楼层

指定HTTP请求头

import crypt;
import web.rest.jsonLiteClient;

var restClient = web.rest.jsonLiteClient();  

//如果所有请求都要添加的相同HTTP头,在这里指定
restClient.addHeaders = {
    [
"Test"] = "test"
}

/*
如果每次请求都要修改HTTP头,可以写到这个事件里.

*/

restClient.beforeRequestHeaders =
function(params){

   
var apiKey = "";
   
var secretKey = "";
   
var authorization = {
        [
"apiKey"] = apiKey;
        [
"time"] = tonumber(time());
    }
   
    authorization[
"sign"] = crypt.md5(apiKey ++ secretKey ++ authorization.time)
   
   
//通过返回值设置本次请求的HTTP头, Content-Type不需要指定(会自动指定)
    return {
        [
"Authorization"] = crypt.encodeBin(web.json.stringify(authorization))
    };
}

var jsonData = restClient.post("http://eu.httpbin.org/post",{
    用户名 =
"用户名";
    密码 =
"密码";
} )

import console;
console.dumpJson(jsonData)
console.pause(
true);

回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2017-11-9 15:43:50 | 显示全部楼层

一个multipart/form-data表单提交的例子:

补一个multipart/form-data表单提交的例子:
http://bbs.aardio.com/forum.php?mod=viewthread&tid=13629
import console;
import web.rest.client;
import string.html;

var http = web.rest.client();
http.api(
"https://oa.tongda2000.com/logincheck.php").post(
     UNAME=
"lijia";
     encode_type=1;
);

http.sendMultipartForm( {
        TO_ID =
"912";
        TO_NAME =
"王征";
        SUBJECT =
"测试邮件标题!";
        SEND_FLAG = 1;
        SMS_REMIND =
"on";
        FROM_WEBMAIL =
"abc@263.net";
        TD_HTML_EDITOR_CONTENT=
/*测试邮件内容*/
    }
    ,
function(str,sendSize,contentLength){
        console.log(
"正在向服务器提交数据",math.size64(sendSize).format() );
    }
);

var html = http.api("https://oa.tongda2000.com/general/email/new/submit.php").post()
console.log( string.html.toText(html) );
console.pause(
true);


回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2020-1-21 14:56:26 | 显示全部楼层

HTML抓取与修改

import win.ui;
/*DSG{{*/
var winform = win.form(text="贴吧抓取工具";right=1141;bottom=791;bgcolor=16777215)
winform.add(
btnGet={cls=
"button";text="抓取";left=246;top=4;right=336;bottom=32;dl=1;dt=1;z=2};
cmbKeyWord={cls=
"combobox";left=85;top=5;right=232;bottom=31;dl=1;dt=1;edge=1;items={};mode="dropdown";z=4};
lbKeyWord={cls=
"static";text="吧名:";left=6;top=8;right=62;bottom=30;align="right";dl=1;dt=1;transparent=1;z=3};
static={cls=
"static";left=10;top=46;right=1120;bottom=788;db=1;dl=1;dr=1;dt=1;transparent=1;z=1}
)
/*}}*/

import web.form;
var wb = web.form(winform.static);

import web.json;
import string.html;
import web.rest.client;

var http = web.rest.client()
var tieba = http.api("http://tieba.baidu.com/f?ie=utf-8&kw={kw}","GET"
    ,
`id="pagelet_html_frs-list/pagelet/thread_list" style="display\:none;">\<\!--(.+?)--\>`)

winform.cmbKeyWord.items = {
"吧名1";"吧名2"}
winform.cmbKeyWord.selIndex = 1;

winform.btnGet.oncommand =
function(id,event){
   
var kw = winform.cmbKeyWord.text;
   
if(!#kw){
        
return winform.msgboxErr("请输入关键字")
    }
     
   
var htmlNew =  /*
    <!doctype html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <style type="text/css">
        html,body{ height:100%; margin:0;font: 14px/1.6 Segoe UI, Tahoma, Arial, "Microsoft YaHei";}
        .info{font-size:12px;color:#999;}
        </style>
    </head>
    <body>
    </body>
    */

   
var htmlNewDoc = string.html(htmlNew);
   
var bodyNew = htmlNewDoc.queryEle(tagName="body");
   
   
var html = tieba[kw](pn=0)
   
var threadList  = string.splitEx(html,`<\<li\s+class\=\"\s*j_thread_list>?=`)
   
for(i=1;#threadList;1){
        
var htmlDoc = string.html( threadList[ i ] )
        
var li = htmlDoc.queryEle(["class"]="j_thread_list";["tagName"]="li")
        
if(!li) continue;
      
      
        
var a = li.queryEle(["class"]="j_th_tit";["tagName"]="a")
        a.href =
"https://tieba.baidu.com" + a.href;
        
        
var content = li.queryEle(["class"]="threadlist_abs threadlist_abs_onlyline";["tagName"]="div");
        
if(content && content[1]){
            a.title = content[1].text;
        }
        
        bodyNew.pushElement(a)
        
        
var dataField=web.json.parse(string.html.ncr(li["data-field"]));
        
var threadInfo = "作者:"+(dataField.author_nickname || dataField.author_name) +" 回复数:" + dataField.reply_num;
        
var replyer = li.queryEle(["class"]="tb_icon_author_rely j_replyer";["tagName"]="span")
        
if(replyer){
            threadInfo = threadInfo +
" " + replyer.title;
        }
         
        bodyNew.pushElement([
"tagName"]="span";["class"]="info").pushElement(text=threadInfo);
        bodyNew.pushElement([
"tagName"]="br")
    }   

    wb.html =
tostring(htmlNewDoc)
}

import process;
wb.translate =
function( url ){
   
import process;
    process.openUrl(url)
}

wb.NewWindow3 =
function(ppDisp,cancel,dwFlags,bstrUrlContext,bstrUrl ) {  
   
return ppDisp,true;
};

winform.show();
win.loopMessage();

回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2020-1-21 14:57:21 | 显示全部楼层

jsonstore演示

import console;
import web.rest.jsonClient;

var http = web.rest.jsonClient();

//打开https://www.jsonstore.io免费获取自动分配的API地址
var jsonstore = http.api(
"https://www.jsonstore.io/e5fd2bdf0e6b3ba3fe4aa61eebd11740cf2fe10e7fad1b5d2fb77c876498baf5");

//增,以POST方法请求网址 https://www.jsonstore.io/e5fd2bd ... 7c876498baf5/user/1
var result = jsonstore.user[1].post(
    name =
"jon.snow";
    age = 31;
)

//改,以PUT方法请求网址 https://www.jsonstore.io/e5fd2bd ... 6498baf5/user/1/age
var result = jsonstore.user[1].age.put(32);

//查
var result = jsonstore.user[1].get();

//删
var result = jsonstore.user[1].delete();
console.dump(result,http.lastRequestUrl);

//也可以在网址中使用大括号指定占位符
var jsonstore = http.api("https://www.jsonstore.io/{id}/{name}");

//API对象的成员名会被自动按顺序替换为URL占位符(忽略占位符的名字)
var result = jsonstore["e5fd2bdf0e6b3ba3fe4aa61eebd11740cf2fe10e7fad1b5d2fb77c876498baf5"].user.get()
//以GET方法请求网址 https://www.jsonstore.io/e5fd2bd ... b77c876498baf5/user

//也可以用一个表指定多个占位符的替换值
var data ={
    id =
"e5fd2bdf0e6b3ba3fe4aa61eebd11740cf2fe10e7fad1b5d2fb77c876498baf5";
    name =
"user";
}
var result = jsonstore[ data ] .get()

console.dump(result)
console.pause()


回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2020-1-21 14:58:07 | 显示全部楼层

jsonLiteClient演示

import win.ui;
/*DSG{{*/
var winform = win.form(text="获取取京东商品评论";right=1189;bottom=593)
winform.add(
edit={cls=
"edit";left=10;top=6;right=1179;bottom=575;db=1;dl=1;dr=1;dt=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=1}
)
/*}}*/

import web.rest.jsonLiteClient;
var http = web.rest.jsonLiteClient()

http.referer =
"https://item.jd.com/"
var jdClub = http.api("https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv13283")

var data = jdClub.get(
    productId=
"100004253893"; // 商品编号
    sortType=6; // 5表示推荐排序,6为按时间排序
    isShadowSku=0; // 仅显示当前商品评论
    score=3; // 好评
    page=1; // 分页索引
    pageSize=10;
    fold=1;
    rid=0;
)

winform.edit.print(data);

winform.show()
win.loopMessage();

回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2020-1-21 15:08:34 | 显示全部楼层

论坛部分 web.rest 相关帖子

aardio几句代码实现 WebDriver 协议客户端
http://bbs.aardio.com/forum.php?mod=viewthread&tid=22543

获取百度网盘下载链接( 已更新不使用浏览器控件 )
http://bbs.aardio.com/forum.php?mod=viewthread&tid=22506


自动抓取下载链接、调用百度网盘批量离线下载(已更新)
http://bbs.aardio.com/forum.php?mod=viewthread&tid=31060


百度自然语言接口调用演示(免费不限调用次数)
http://bbs.aardio.com/forum.php?mod=viewthread&tid=22479


百度开放平台API调用
http://bbs.aardio.com/forum.php?mod=viewthread&tid=22093


QQ登录查询小工具源码
http://bbs.aardio.com/forum.php?mod=viewthread&tid=13525


【分享】初步实现钉钉和公司WEB系统集成后扫码登陆
http://bbs.aardio.com/forum.php?mod=viewthread&tid=13773


解析格式化HTML演示
http://bbs.aardio.com/forum.php?mod=viewthread&tid=22516


Chrome远程调试接口调用演示
http://bbs.aardio.com/forum.php?mod=viewthread&tid=21977


分享下科大讯飞在线朗读文字
http://bbs.aardio.com/forum.php?mod=viewthread&tid=22242


熊猫直播平台弹幕获取
http://bbs.aardio.com/forum.php?mod=viewthread&tid=22220


Google搜索助手
http://bbs.aardio.com/forum.php?mod=viewthread&tid=12950


一次分析下载广场舞视频的过程附源码......
http://bbs.aardio.com/forum.php?mod=viewthread&tid=22550


百度短网址生成源码
http://bbs.aardio.com/forum.php?mod=viewthread&tid=10511


域名备案批量查询
http://bbs.aardio.com/forum.php?mod=viewthread&tid=9729


快盘调用接口
http://bbs.aardio.com/forum.php?mod=viewthread&tid=8059


如何通过HTTP地址读写服务器上的phpstudy数据
http://bbs.aardio.com/forum.php?mod=viewthread&tid=13693
回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2020-1-21 15:09:23 | 显示全部楼层

百度API测试

import win.ui;
/*DSG{{*/
var winform = win.form(text="百度API测试";right=747;bottom=463)
winform.add(
button={cls=
"button";text="文字识别";left=596;top=411;right=731;bottom=449;db=1;dr=1;z=3};
edit={cls=
"edit";left=16;top=18;right=731;bottom=379;autohscroll=false;db=1;dl=1;dr=1;dt=1;edge=1;multiline=1;vscroll=1;z=1};
editUrl={cls=
"edit";left=16;top=415;right=591;bottom=447;align="right";db=1;dl=1;dr=1;edge=1;z=2};
static={cls=
"static";text="请输入图像文件路径(可直接拖放文件到窗口上):";left=21;top=392;right=234;bottom=407;db=1;dl=1;transparent=1;z=4}
)
/*}}*/

winform.button.oncommand =
function(id,event){
   
     winform.button.disabledText =
"正在识别中"
   
    thread.invoke(
        
function(winform){
            
            
import baidu.client;
            
var http =  baidu.client();
            
            
/*
            支持下面三种写法:
            
            http.setAuth( 这里直接写access_token )
            http.setAuth( 这里写一个可以获取access_token的网址 )
            http.setAuth( "你自己的API Key","你自己的Secret Key" )
            )
            */

            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.accurate_basic(
                image = winform.editUrl.text;
            )
            
            
for i,v in table.eachIndex(result.words_result){
                winform.edit.appendText(v.words)
            }  
            
            winform.button.disabledText =
null;
        },winform
    )
}

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

winform.show()
win.loopMessage();

回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2020-1-21 15:09:56 | 显示全部楼层

百度文本转语音接口(无限制免费调用)

import win.ui;
/*DSG{{*/
winform = win.form(text=
"百度文本转语音接口(无限制免费调用)";right=553;bottom=334)
winform.add(
button={cls=
"button";text="语音合成";left=393;top=285;right=540;bottom=321;z=1};
cbPer={cls=
"combobox";left=398;top=248;right=534;bottom=272;edge=1;items={};mode="dropdownlist";z=4};
edit={cls=
"edit";text='真的"666"';left=17;top=24;right=377;bottom=311;autohscroll=false;edge=1;multiline=1;vscroll=1;z=3};
groupbox={cls=
"groupbox";text="预转换的文字";left=7;top=1;right=387;bottom=322;edge=1;z=2}
)
/*}}*/

var wmPlay = com.CreateObject("WMPlayer.OCX");
winform.button.oncommand =
function(id,event){
   
   
var http = baidu.speech();
   
   
/*
    支持下面三种写法:
    http.setAuth( 这里直接写access_token )
    http.setAuth( 这里写一个可以获取access_token的网址 )
    http.setAuth( "hkMI2fBTaKHDLolNxkPw7ylQ","tbUgpyqX9MiCE0LKozGFaGRoLS7xZHqs" )
    )
    */

    http.setAuth(
"hkMI2fBTaKHDLolNxkPw7ylQ","tbUgpyqX9MiCE0LKozGFaGRoLS7xZHqs" )
   
   
var mp3Url,err = http.text2audio(
        tex = winform.edit.text;
        per = winform.cbPer.selText;
    )
            
    wmPlay.Url =  mp3Url;
    wmPlay.controls.play();
}

import baidu.speech;
winform.cbPer.items = baidu.speech.voices;

winform.show();
win.loopMessage();

回复

使用道具 举报

188

主题

2546

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
14118
 楼主| 发表于 2020-1-21 15:10:49 | 显示全部楼层

英语语法&#65279;解析&#65279;工具

import fonts.fontAwesome;
import win.ui;
/*DSG{{*/
var winform = win.form(text="英语语法&#65279;解析&#65279;工具 ( 点击语法树节点自动选中源文本, 文本框右键菜单增加翻译、朗读、搜索等 )";right=890;bottom=811;parent=...)
winform.add(
btnParse={cls=
"button";text="解析语法";left=735;top=97;right=853;bottom=143;dr=1;dt=1;font=LOGFONT(name='FontAwesome');z=3};
editMessage={cls=
"richedit";left=14;top=89;right=721;bottom=151;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-16);hidesel=false;hscroll=1;multiline=1;vscroll=1;z=4};
editText={cls=
"richedit";text="I want to go home";left=14;top=6;right=871;bottom=66;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-16);hidesel=false;hscroll=1;multiline=1;vscroll=1;z=2};
lbTranslate={cls=
"static";left=13;top=68;right=879;bottom=86;dl=1;dr=1;dt=1;transparent=1;z=6};
treeview={cls=
"treeview";left=17;top=184;right=874;bottom=804;asel=false;bgcolor=15793151;db=1;dl=1;dr=1;dt=1;edge=1;hscroll=1;infoTip=1;vscroll=1;z=1};
wmplayer={cls=
"static";text="wmplayer";left=6;top=822;right=216;bottom=856;db=1;dl=1;transparent=1;z=5}
)
/*}}*/

import web.json;
winform.treeview.onnotify =
function(id,code,ptr){
   
if( code == 0xFFFFFE3D/*_TVN_SELCHANGEDW*/ ){
        
var hItem = winform.treeview.getSelection();
        
if(hItem){
            winform.editMessage.text = winform.treeview.getItemText(hItem)
            
var data  = winform.treeview.getItemData(hItem);
            
            
if(type(data)!=type.table){
                hItem = winform.treeview.getParentItem(hItem)
                data  = hItem ? winform.treeview.getItemData(hItem);
            }
               
            
if(type(data)==type.table){  
               
if(data.index && data.pos && data.token){
                    
var text = winform.editText.text;
                    
var index = 0;
                    
for i,j in string.gmatch(text ,"()\w+()") {
                        index++;
                        
if(index==data.index){
                            winform.editText.setsel(i,j-1)
                           
break ;
                        }
                    }
                    
                }
            }
        }
    }
   
elseif(code = 0xFFFFFFFB/*_NM_RCLICK*/){
        
var hItem,tvht = winform.treeview.hitTest();
        winform.treeview.setSelected(hItem);
        
        
var menu = win.ui.popmenu(winform)
        menu.add(
"删除",
            
function(){
                winform.treeview.delItem(hItem)
            }
        )
        menu.popup(x,y,
true);
    }
}

var parser = function(winform){
    winform.btnParse.disabledText = {
'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}
   
   
import youdao.fanyi;
   
var fanyi = youdao.fanyi();
    winform.lbTranslate.text = fanyi.translate(winform.editText.text)[[
"translateResult"]][[1]][[1]][["tgt"]];

   
import parseyMcParseface;
   
var deepAi = parseyMcParseface.deepAi();   
   
   
var result = deepAi.parseymcparseface(sentence=winform.editText.text)
    winform.treeview.parseData = result;
   
    result = table.mapr(result,
function(v,k,result){
        
if(k=="pos"){
            
var en,zh = parseyMcParseface.pos.tag.en[v],parseyMcParseface.pos.tag.zh[v]
            
if(en&&zh){
               
return zh[1] + " " + en[1]  
            }
        }
        
if(k=="label"){
            
var en,zh = parseyMcParseface.pos.label.en[v],parseyMcParseface.pos.label.zh[v]
            
if(en&&zh){
               
return v + " " + zh[1] + " " + en[1]  
            }  
        }
        
if(k=="dep"){
            
return parseyMcParseface.dep.zh[k][1];
        }
        
        
return v;
    })
   
   
if(result && result.output){
        winform.treeview.insertTable(result.output[1])
        winform.treeview.afterParse();      
    }   
   
else {
        winform.editMessage.text =
"遇到错误,试试输入单句,不要提交大段英文"
    }
   
    winform.btnParse.disabledText =
null;
}

import parseyMcParseface;
winform.treeview.afterParse =
function(){
    winform.treeview.enum(
        
function(hItem,parent){
            
var str = winform.treeview.getItemText(hItem);
            
var zh,en = parseyMcParseface.dep.zh[str],parseyMcParseface.dep.en[str]
            
if(zh && en){
                winform.treeview.setItemText(hItem,str +
": " + zh[1] + " " + en[1]);
            }
        }
    )
   
    winform.treeview.expandAll()   
}
   
winform.btnParse.oncommand =
function(id,event){
    thread.invoke(parser,winform)
}

import process;
import inet.url;
var editMenu = {
    {
/*---分隔线---*/ };
    {
"翻译/朗读";
        
function(id){
            
var word = winform.editText.selText;
            
if(!#word){
                word = winform.editText.text;
            }
            
            
import youdao.fanyi;
            
var fanyi = youdao.fanyi();
            
var result = fanyi.translate(word)[["translateResult"]][[1]][[1]];
            
if(result){
                winform.wmplayer._object.url =
"http://fanyi.baidu.com/gettts?lan=en&text="
                    + inet.url.encode(word)
                    +
"&spd=3&source=web"
                winform.lbTranslate.text = string.concat(result[[
"tgt"]]," (",result[["src"]],")");
            }
            
else {
                winform.lbTranslate.text =
"翻译接口错误"
            }
            
            fanyi.http.close()
        }
    };
    {
/*---分隔线---*/ };
    {
"Google翻译";
        
function(id){
            
var word = winform.editText.selText;
            
if(!#word){
                word = winform.editText.text;
            }
            
            
var url = "https://translate.google.cn/#en/zh-CN/" + inet.url.encode(word);
            process.openUrl(url);
        }
    };
    {
"百度翻译";
        
function(id){
            
var word = winform.editText.selText;
            
if(!#word){
                word = winform.editText.text;
            }
            
            
var url = "https://translate.google.cn/#en/zh-CN/" + inet.url.encode(word);
            process.openUrl(url);
        }
    };
    {
/*---分隔线---*/ };
    {
"Google搜索";
        
function(id){
            
var word = winform.editText.selText;
            
if(!#word){
                word = winform.editText.text;
            }
            
            
var url = "https://www.google.com/search?q=" + inet.url.encode(word);
            process.openUrl(url);
        }
    };
    {
"百度搜索";
        
function(id){
            
var word = winform.editText.selText;
            
if(!#word){
                word = winform.editText.text;
            }
            
            
var url = "https://www.baidu.com/s?ie=utf-&wd=" + inet.url.encode(word);
            process.openUrl(url);
        }
    };
}

winform.editText.enablePopMenu(editMenu);
winform.editMessage.enablePopMenu(editMenu);
winform.wmplayer = winform.wmplayer.createEmbed(
"WMPlayer.OCX");

winform.show()
win.loopMessage();

回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2020-5-31 19:57 , Processed in 0.078125 second(s), 25 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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