はじめに
LINEbotで、ドイツ語から英語と日本語への翻訳ボットを以前に作りました。
次は、ドイツ料理とかドイツの建築物の写真から、それが一体何なのか情報を気軽に取れたらいいなと感じています。GoogleさんのAIの力をお借りしてつくってみます。
◆YouTubeでの解説↓
https://youtu.be/u_NcB1rtsPU
今回使うURLたち
◆ドイツ語から英語と日本語への翻訳ボット(この続きです)
https://zenn.dev/njn0te/articles/a6c0d8640cdede
◆Google Cloud Vision API (Vision AI)
https://cloud.google.com/vision
◆LINE Developers
https://developers.line.biz/
GCPの下準備
まずはGoogle Cloud Platformにアクセスしてください。
https://console.cloud.google.com/
左上の「ナビゲーション メニュー」から「API とサービス」の「ライブラリ」を選択。
ライブラリの中から「Cloud Vision API」を見つけて、有効にしてください。
※1000回のアクセスまで無料
もう一度、「ナビゲーション メニュー」から「API とサービス」の「認証情報」を選択。
「認証情報を作成」から「APIを作成」を押して、キーを下記のプログラムにコピペして使います。
※本番環境での不正利用を回避するため、「Cloud Vision API」にチェックを入れてキーを制限してください。
プログラム
'*************'の部分を適切な値にしてご利用ください。
// 応答メッセージURL
const REPLY = "https://api.line.me/v2/bot/message/reply";
// アクセストークン
const ACCESS_TOKEN = '*************';
// スプレッドシート情報
const SHEET_ID = '*************';
const SHEET_URL = 'https://docs.google.com/spreadsheets/d/*************/edit#gid=0';
const SHEET_LOG = SpreadsheetApp.openById(SHEET_ID).getSheetByName('検索履歴');
// VISION AI で Googleドライブにアクセス
const GOOGLE_DRIVE_ID = '*************';
const CLOUD_VISION_API_KEY = '*************';
function doPost(e) {
//メッセージ受信
const data = JSON.parse(e.postData.contents).events[0];
//ユーザーID取得
const lineUserId = data.source.userId;
// リプレイトークン取得
const replyToken = data.replyToken;
// 送信されたメッセージの種類を取得
const postType = data.message.type;
// 送信されたメッセージ取得
const postMsg = data.message.text;
// LINEに送信
let replyMsg;
if ( "image" === postType ) {
replyMsg = LanguageApp.translate(imageSave(replyToken, lineUserId, data), 'en','ja');
} else {
// 翻訳
const lang = 'de';
const englishMsg = LanguageApp.translate(postMsg, lang,'en');
const japaneseMsg = LanguageApp.translate(postMsg, lang,'ja');
const franceMsg = LanguageApp.translate(postMsg, lang,'fr');
// 検索履歴にユーザーID、原文、翻訳(英語・日本語)、日時を記載
debugLog(lineUserId, postMsg, englishMsg, japaneseMsg, franceMsg);
replyMsg = `EN: ${englishMsg}\nJA: ${japaneseMsg}\nFR: ${franceMsg}`
}
sendMessage(replyToken, replyMsg);
}
function imageSave(replyToken, lineUserId, data) {
const IMG_DATA = getImg(data); // LINEから画像取得
const IMG_INFO = saveImg(IMG_DATA, lineUserId); // Googleドライブに保存
const ANA_MSG = analyseMsg(IMG_INFO.encodedFile); // 解析
return ANA_MSG;
}
function getImg(data) {
const IMG_URL = 'https://api-data.line.me/v2/bot/message/' + data.message.id + '/content';
const HEAD = {
"method":"get",
"headers": {
"Authorization" : "Bearer " + ACCESS_TOKEN
}
}
const IMG_DATA = UrlFetchApp.fetch(IMG_URL, HEAD);
return IMG_DATA;
}
function saveImg(imgBinary, lineUserId){
const FOLDER = DriveApp.getFolderById(GOOGLE_DRIVE_ID);
const FILE_NAME = Math.random().toString(36).slice(-8);
const IMAGE_FILE = FOLDER.createFile(imgBinary.getBlob().setName(FILE_NAME));
const IMAGE_URL = 'https://drive.google.com/uc?export=view&id=' + IMAGE_FILE.getId();
const FETCH_IMG = Utilities.base64Encode(UrlFetchApp.fetch(IMAGE_URL).getContent());
IMAGE_FILE.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
const IMG_INFO = {
folder : FOLDER,
file : IMAGE_FILE,
encodedFile : FETCH_IMG
}
return IMG_INFO;
}
function analyseMsg(contents) {
const URL = `https://vision.googleapis.com/v1/images:annotate?key=${CLOUD_VISION_API_KEY}`;// ウェブ エンティティおよびページの検出
const BODY = {
"requests":[
{
"image": {
"content": contents
},
"features":[
{
"type":"WEB_DETECTION",
}
]
}
]
};
const HEAD = {
"method":"post",
"contentType":"application/json",
"payload":JSON.stringify(BODY),
"muteHttpExceptions": true
};
let response = UrlFetchApp.fetch(URL, HEAD);
let description = '';
// 画像検出
if(JSON.parse(response).responses[0].webDetection) {
if (JSON.parse(response).responses[0].webDetection.hasOwnProperty('webEntities')){
let x = JSON.parse(response).responses[0].webDetection.webEntities.length;
for ( let i = 0; i < x; i++ ) {
const Entities = JSON.parse(response).responses[0].webDetection.webEntities[i].description;
const EntScore = JSON.parse(response).responses[0].webDetection.webEntities[i].score;
if (Entities != null && EntScore > 0.5) {
description += "・" + Entities + "\n";
}
}
if(description == ""){
description = "関連性が薄い情報のみです";
}
}else{
description = "情報がありません。";
}
}
console.log(description)
return description;
}
function debugLog(userId, text, eng, jap, fra) {
const date = Utilities.formatDate( new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
SHEET_LOG.appendRow([userId, text, eng, jap, fra, date]);
}
function sendMessage(replyToken, replyText) {
const postData = {
"replyToken" : replyToken,
"messages" : [
{
"type" : "text",
"text" : replyText
}
]
};
const headers = {
"Content-Type" : "application/json; charset=UTF-8",
"Authorization" : "Bearer " + ACCESS_TOKEN
};
const options = {
"method" : "POST",
"headers" : headers,
"payload" : JSON.stringify(postData)
};
return UrlFetchApp.fetch(REPLY, options);
}