最新のコードと手順書は、Githubにあります
Messege API
アクセストークンをコピーしておく
Face API
1分あたり20トランザクションまで、できるため、とりあえずはFree価格で十分足りる
価格 - Face API | Microsoft Azure
KEYをコピーしておく
Function App
- 新規作成
HttpTriggerの関数を作成
LINEから来たメッセージを処理する関数
- [新しい関数]を選択
-
HttpTrigger
のテンプレートを選択 - 言語:
JavaScript
、承認レベルはFunction
の関数を作成 - [開発]タブを選択し、LINEからHTTP送信されたBodyを
Azure Queue Storage
に設定する処理を追加(index.js) -
Azure Queue Storage
へのバインド設定を追加する(function.js)
関数名: HttpTriggerJS1
Azure Queue Storage: outputQueueItem
キュー名: js-queue-items
ストレージアカウント接続: AzureWebJobsDashboard
index.js
module.exports = function (context, req) {
context.bindings.outputQueueItem = req.body;
res = { body : "" };
context.done();
};
function.js
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "$return"
},
{
"type": "queue",
"name": "outputQueueItem",
"queueName": "js-queue-items",
"connection": "AzureWebJobsDashboard",
"direction": "out"
}
],
"disabled": false
}
QueueTriggerの関数を作成
キューに設定された内容を処理する関数を作成
- [新しい関数]を選択
-
QueueTrigger
のテンプレートを選択 - 言語:
JavaScript
、関数HttpTriggerJS1と一致するキュー名
とストレージアカウント接続
を入力し関数を作成 - [開発]タブを選択し、
Azure Queue Storage
に設定された内容を取得し、画像ならFaceAPIに渡し、年齢をLINEに送信する処理を追加(index.js)
関数名: QueueTriggerJS1
キュー名: js-queue-items (関数HttpTriggerJS1と一致)
ストレージアカウント接続: AzureWebJobsDashboard (関数HttpTriggerJS1と一致)
index.js
const https = require('https');
const url = require('url');
const FACE_API = 'https://australiaeast.api.cognitive.microsoft.com/face/v1.0/detect?returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=age,gender,smile';
/**
* JavaScript queue trigger function processed work item
* @param {*} context
* @param {*} myQueueItem
*/
module.exports = function(context, myQueueItem) {
myQueueItem.events.forEach((event) => postMessage(context, event));
context.done();
};
/**
* Determining the message type
* @param {*} context
* @param {*} event
*/
function postMessage(context, event) {
var messageType = event.message.type;
if (messageType === 'text') {
postLineMessage(context, event, '画像をおくってください');
// postCognitiveUrl(context, event);
} else if (messageType === 'image') {
getImageData(context, event)
.then((postData) =>{
postCognitiveImage(context, event, postData);
})
.catch((err) => {
context.log(err);
postCognitiveImage(context, event, err);
});
} else if (messageType === 'sticker') {
postLineMessage(context, event, '画像をおくってください');
} else {
postLineMessage(context, event, '画像をおくってください');
}
}
/**
* Send image data to Face API
* @param {*} context
* @param {*} event
* @param {*} postData
*/
function postCognitiveImage(context, event, postData) {
var parseUrl = url.parse(FACE_API);
var postOptions = {
host: parseUrl.host,
path: parseUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream',
'Content-Length': postData.length,
'Ocp-Apim-Subscription-Key': process.env.COGNITIVE_KEY,
},
};
var bodyString = null;
var req = https.request(postOptions, function(res) {
context.log('STATUS: ' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function(chunk) {
bodyString = chunk;
}).on('end', function() {
if (res.statusCode !== 200 || bodyString === '[]') {
postLineMessage(context, event, '顔が認識できませんでした');
} else {
var result = JSON.parse(bodyString);
var age = result[0].faceAttributes.age;
postLineMessage(context, event, age + '歳');
}
});
});
req.write(postData);
req.end();
}
/**
* Send message to LINE
* @param {*} context
* @param {*} event
* @param {*} msg
*/
function postLineMessage(context, event, msg) {
var jObj = {};
jObj.type = 'text';
jObj.id = event.message.id;
jObj.text = msg;
var postData = JSON.stringify({
'replyToken': event.replyToken,
'messages': [jObj],
});
var parseUrl = url.parse('https://api.line.me/v2/bot/message/reply');
var postOptions = {
host: parseUrl.host,
path: parseUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {' + process.env.LINE_CHANNEL_ACCESS_TOKEN + '}',
'Content-Length': Buffer.byteLength(postData),
},
};
var req = https.request(postOptions);
req.write(postData);
req.end();
}
/**
* Retrieve image data from LINE
* @param {*} context
* @param {*} event
*/
function getImageData(context, event) {
return new Promise((resolve, reject) => {
var messageId = event.message.id;
var parseUrl = url.parse('https://api.line.me/v2/bot/message/' + messageId + '/content');
var postOptions = {
host: parseUrl.host,
path: parseUrl.path,
method: 'GET',
headers: {
'Content-type': 'application/json',
'Authorization': 'Bearer {' + process.env.LINE_CHANNEL_ACCESS_TOKEN + '}',
},
};
var req = https.request(postOptions, function(res) {
var data = [];
res.on('data', function(chunk) {
data.push(new Buffer(chunk));
}).on('error', function(err) {
context.log(err);
postLineMessage(context, event, err);
reject(err);
}).on('end', function() {
var postData = Buffer.concat(data);
resolve(postData);
});
});
req.end();
});
}
function.js
{
"bindings": [
{
"name": "myQueueItem",
"type": "queueTrigger",
"direction": "in",
"queueName": "js-queue-items",
"connection": "AzureWebJobsDashboard"
}
],
"disabled": false
}
※ コードはエラー処理も足りないと思うので自己責任で、コピーまたは、編集してください
それぞれのアプリケーションを接続
-
Function API
のアプリケーション設定を開く - アプリ設定に
Face API
のKEY、とLINEのMessaging API
のKEYを環境変数に設定 - HttpTriggerの関数のURL(エンドポイント)をコピーする
- LINEの
Messaging API
のWebhookにFunction App
のエンドポイントを指定する
環境変数 | KEY |
---|---|
COGNITIVE_KEY | FaceAPIのKEY |
LINE_CHANNEL_ACCESS_TOKE | Messaging APIのアクセストークン |
画像をLINEBoTに送信してみる
年齢が返ってくれば成功
以下は、フリー画像の美少女さんを使わせて頂いています