最近、あまりコードが書けていないのですが、仕事の方があまりにも非効率極まりなくなってきたので、ToDo管理システムを構築してやろうと思っているのですが、既存のツールだけだとどうしても「手書きメモ」のリマインドがもれるので、どうにかしてやろうと思ったのです。
作ろうと思っているシステム
GoodNotesでメモを書き出す→Google Driveに保存→Google Apps Scriptで定期的にGoogle Vision APIを叩いて、メモを取得する→ToDoを登録
という野望を持っているわけです。
参考にした資料
Google Vision APIはGoogle Apps Scriptには標準で用意されていないので、APIを直接叩きます。既に同様のことが記事になっていました。
(参考記事:Google Apps ScriptでCloud Vision APIを使ってみる)
本日のコード.gs
ほぼ、参考サイトのコピペです。なんかすみません…。特定のフォルダにある画像ファイルを順番にVision APIに通しています。
function doGet(e) {
var url = "https://accounts.google.com/o/oauth2/auth";
var client_id = PropertiesService.getScriptProperties().getProperty("client_id");
var accessToken = PropertiesService.getScriptProperties().getProperty("access_token");
if(accessToken == null) {
//必要なパラメータ郡
var param = {
"response_type" : "code",
"client_id" : client_id,
"redirect_uri" : getCallbackURL_(), //←は↓に書いてあります
"state" : ScriptApp.newStateToken().withMethod("callback").withArgument("name", "value").withTimeout(2000).createToken(), //←の指定で/usercallbackが呼び出された後、callback関数を呼び出し、その際nameというパラメータでvalueという値を渡し 2000秒でタイムアウトになるという設定が可能になります。
"scope" : "https://www.googleapis.com/auth/cloud-vision",
"access_type" : "offline",
"approval_prompt": 'force'
};
var params = [];
for(var name in param){
params.push(name + "=" + encodeURIComponent(param[name]));
}
url = url + "?" + params.join("&");
Logger.log(url);
return HtmlService.createHtmlOutput('<a href="' + url + '" target="_blank">認証</a>') ;
} else {
return HtmlService.createHtmlOutput('<p>設定済みです。</p>');
}
}
function getCallbackURL_(){
var url = ScriptApp.getService().getUrl() ;
if ( url.indexOf('/exec') >= 0 ) return url.slice(0, -4) + 'usercallback' ;
return url.slice(0, -3) + 'usercallback' ;
}
function callback(e) {
var credentials = fetchAccessToken_(e.parameter.code) ;
var scriptProperties = PropertiesService.getScriptProperties() ;
Logger.log(credentials);
scriptProperties.setProperty('access_token', credentials.access_token) ;
scriptProperties.setProperty('refresh_token', credentials.refresh_token) ;
return HtmlService.createHtmlOutput('<p>設定しました。</p>');
}
function fetchAccessToken_(code) {
var prop = PropertiesService.getScriptProperties();
var res = UrlFetchApp.fetch("https://accounts.google.com/o/oauth2/token", {
"method" : "POST",
payload : {
"code" : code,
"client_id" : prop.getProperty("client_id"),
"client_secret" : prop.getProperty("client_secret"),
"redirect_uri" : getCallbackURL_(),
"grant_type" : "authorization_code"
},
muteHttpExceptions : true
});
return JSON.parse(res.getContentText());
}
function todoDetection() {
var targetFolder = PropertiesService.getScriptProperties().getProperty("target_folder");
var folder = Drive.Children.list(targetFolder, {q: "trashed=false"});
for(var i = 0; i < folder.items.length; i++) {
var target = Drive.Files.get(folder.items[i].id);
var file = DriveApp.getFileById(target.id);
var result = imageAnnotate(file);
if(!result) {
Logger.log("target file name = " + target.title);
}
}
}
function imageAnnotate(file){
var accessToken = PropertiesService.getScriptProperties().getProperty("access_token");
var payload = JSON.stringify({
"requests":[
{
"image": {
"content": Utilities.base64Encode(file.getBlob().getBytes())
},
"features": [
{
"type": "TEXT_DETECTION",
"maxResults": 100
}
],
}
]
});
try {
var res = UrlFetchApp.fetch("https://vision.googleapis.com/v1/images:annotate",
{
method : 'post',
headers: {
authorization: 'Bearer ' + accessToken
},
contentType: 'application/json',
payload : payload
});
} catch(e) {
// 失敗
Logger.log(e);
return false;
}
var obj = JSON.parse(res.getContentText());
var res = obj.responses;
for(var i = 0; i < res.length; i++) {
// Logger.log(res[i].textAnnotations);
var textAnnotations = res[i].textAnnotations;
for(var j = 0; j < textAnnotations.length; j++) {
Logger.log(textAnnotations[j].description);
}
}
return true;
}
結果
iPadのGoodNotesで出力した画像では、正しく認識しませんでした。文章の一部が文字に起こせたものもありましたが、実用には不十分でした。紙に書いたものをスキャナで取れば、もう少し精度があがるんでしょうか。そもそも、字が汚いという話もありそうですが…。今後の課題です。
参考資料
http://qiita.com/soundTricker/items/b4df3072088fcbd0e36d
http://qiita.com/wezardnet/items/ebd0c98f3fc04bcc53a0