LoginSignup
5
1

More than 1 year has passed since last update.

GCP の Vision AI を試してみた🐻🐰

Last updated at Posted at 2022-02-25

はじめに

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 とサービス」の「ライブラリ」を選択。
スクリーンショット 2022-02-25 5.43.20.png

ライブラリの中から「Cloud Vision API」を見つけて、有効にしてください。
スクリーンショット 2022-02-25 5.45.26.png
※1000回のアクセスまで無料

もう一度、「ナビゲーション メニュー」から「API とサービス」の「認証情報」を選択。
スクリーンショット 2022-02-25 5.48.01.png

「認証情報を作成」から「APIを作成」を押して、キーを下記のプログラムにコピペして使います。
※本番環境での不正利用を回避するため、「Cloud Vision API」にチェックを入れてキーを制限してください。
スクリーンショット 2022-02-25 5.54.32.png

プログラム

'*************'の部分を適切な値にしてご利用ください。

コード.gs
// 応答メッセージ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);
}

完成したLINE BOT

気ままに新機能は追加していく気がするので、もし良ければ友達追加してね🐻🐰
image.png

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1