iT邦幫忙

0

line bot 回應特定關鍵字(google app script)

  • 分享至 

  • xImage

小弟JS新手,在網路上看到有開源資料開始學習。
以下程式碼掛在google app script給line bot使用,想要讓使用者可以輸入"YYYYMMDD"就能查詢當日活動,其他訊息則略過。
有嘗試在「//開始查詢資訊」前加入if判斷式做break,但是沒有成功,想請各位大神提點,謝謝!

var CHANNEL_ACCESS_TOKEN = "  ";
var spreadSheetId = "  ";    //試算表 ID
var sheetName = ["藝文","優惠"];    //工作表名稱
var searchColumn = [1];    //搜尋第幾欄的資料
var whiteList = [""];  //白名單(允許取得資料的使用者ID
var whiteListMode = 0;    //白名單模式,1 表示需要設定白名單才能進行查詢,0 表示任何人加了好友都可以查詢。
var fuzzySearch = 1;    //模糊搜尋模式,1 表示表格內部分字串相同即取出資料,0 表示儲存格內容完全相同才取出資料。
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);



function doPost(e) {
  var userData = JSON.parse(e.postData.contents);
  var allowed = whiteListMode;
  var clientID = userData.events[0].source.userId;
  var replyToken = userData.events[0].replyToken;
  if ((userData.events[0].type == "follow" || userData.events[0].message.text.toLowerCase() == "findmyid") && whiteListMode === 1) {
    var replyMessage = [{type:"text", text:"您的使用者 ID 是「" + clientID + "」,請將此 ID 告知此官方帳號的擁有者加入白名單後才能開始查詢資料。"}];
    sendReplyMessage(CHANNEL_ACCESS_TOKEN, replyToken, replyMessage);
    return;
  }
  if (userData.events[0].type != "message") {return;}
  if (userData.events[0].message.type != "text") {return;}
  // 檢查是否是允許的用者提出搜尋需求
  for (var i = 0; i < whiteList.length; i++) {
    if (whiteList[i] == clientID) {
      allowed = 0;
      break;
    }
  }

  if (allowed === 1) {
    var replyMessage = [{type:"text", text:"您的使用者 ID 是「" + clientID + "」,請將此 ID 告知此官方帳號的擁有者加入白名單後才能開始查詢資料。"}];
    sendReplyMessage(CHANNEL_ACCESS_TOKEN, replyToken, replyMessage);
    return;
  }



  //開始查詢資訊
  var replyMessage = [];
  var replyToken = userData.events[0].replyToken;
  var searchContent = userData.events[0].message.text;
  for (var i = 0; i < sheetName.length; i++) {
    var searchResult = [];
    var sheet = spreadSheet.getSheetByName(sheetName[i]);
    var lastRow = sheet.getLastRow();
    var lastColumn = sheet.getLastColumn();
    var sheetData = sheet.getSheetValues(1, 1, lastRow, lastColumn);
    for (var j = 0; j < searchColumn.length; j++){
      var searchTemp = sheetData.filter(function(item, index, array){
        if (fuzzySearch == 0) {return item[searchColumn[j] - 1].toString().toLowerCase() === searchContent.toLowerCase();}
        else {return item[searchColumn[j] - 1].toString().toLowerCase().indexOf(searchContent.toLowerCase()) != -1 ;}
      });
      searchResult = searchResult.concat(searchTemp);
    }
    if (searchResult.length > 0) {
      var replyContent = "";
      searchResult = uniqueArrayElement(searchResult);
      replyContent = "在「" + sheetName[i] + "」中搜尋到 " + searchResult.length + " 筆資料";
      for (var k = 0; k < searchResult.length; k++) {
        replyContent += "\n\n" + sheetData[0][0] + ":" + searchResult[k][0];
        for (var l = 1; l < lastColumn; l++) {
          replyContent += "\n" + sheetData[0][l] + ":" + searchResult[k][l];
        }
      }
      replyMessage.push({type:"text", text:replyContent});
    }
    if (replyMessage.length == 5) {break;}
  }
  if (replyMessage.length == 0) {replyMessage.push({type:"text", text:"查詢不到「" + searchContent + "」的資料"});}
  sendReplyMessage(CHANNEL_ACCESS_TOKEN, replyToken, replyMessage);
}


//移除陣列中重複的元素
function uniqueArrayElement(arrayData) {
  var result = arrayData.filter(function(element, index, arr){
    return arr.indexOf(element) === index;
  });
  return result;
}


//回送 Line Bot 訊息給使用者
function sendReplyMessage(CHANNEL_ACCESS_TOKEN, replyToken, replyMessage) {  var url = "https://api.line.me/v2/bot/message/reply";
  UrlFetchApp.fetch(url, {
    "headers": {
      "Content-Type": "application/json; charset=UTF-8",
      "Authorization": "Bearer " + CHANNEL_ACCESS_TOKEN,
    },
    "method": "post",
    "payload": JSON.stringify({
      "replyToken": replyToken,
      "messages": replyMessage,
    }),
  });
}
https://ithelp.ithome.com.tw/articles/10219503
這邊就有解答囉~
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

0
科技君 Shawn
iT邦新手 4 級 ‧ 2021-08-16 23:11:59

樓主應該也是看 Boris 資訊小站的影片吧 XD 我當初也是看同個影片,用同一個程式碼練手。不過對我來說這份程式碼有點小複雜,有點難抓出是什麼問題,但我以你的需求寫了一個新的:


var CHANNEL_ACCESS_TOKEN = "  ";
var spreadSheetId = "  ";    //試算表 ID
var sheetName_1 = "藝文";
var sheetName_2 = "優惠";    //工作表名稱
var search_Column = 1;    //搜尋第幾欄的資料
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
var sheet_1 = SpreadSheet.getSheetByName(sheetName_1); // 第一張資料表的資料
var sheet_2 = SpreadSheet.getSheetByName(sheetName_2); // 第二張資料表的資料
var max_row = sheet_1.getLastRow(); // 取得第一張資料表最後的行數,用於迴圈檢索次數
var max_row_2 = sheet_2.getLastRow(); // 取得第一張資料表最後的行數,用於迴圈次數


function doPost(e) {
    var userData = JSON.parse(e.postData.contents);
    var replyToken = userData.events[0].replyToken;

    if (userData.events[0].type != "message") { return; }
    if (userData.events[0].message.type != "text") { return; }

    //開始查詢資訊
    var replyMessage = []; // 要為JSON 格式~
    var replyToken = userData.events[0].replyToken;

    var search_keyword = userData.events[0].message.text; // 使用者要找的關鍵字 YYYYMMDD

    if (search_keyword != "") {
        // 先看看第一張資料表內有沒有關既字的內容
        for (x = 1; x <= max_row; x++) {
            var sheet_block = sheet_1.getRange(search_Column, x).getValue();
            // 如果有相符內容
            if (search_keyword == sheet_block) {
                reply_block = sheet_1.getRange(2, x).getValue(); // 取得隔壁欄、同一行的資料,若要回傳的資料不在第二欄,更改 getRange 的 2
                replyMessage = [
                    {
                        "type": "text",
                        "text": "找到了!當天的活動:" + reply_block // 回傳活動
                    }
                ]
                break;
            }
            else {
                // 如果沒在第一個工作表找到,會到這個回圈搜尋第二個資料表
                for (x = 1; x <= max_row_2; x++) {
                    var sheet_block = sheet_2.getRange(search_Column, x).getValue();
                    if (search_keyword == sheet_block) {
                        reply_block = sheet_1.getRange(2, x).getValue(); // 若要回傳的資料不在第二欄,更改 getRange 的 2
                        replyMessage = [
                            {
                                "type": "text",
                                "text": "找到了!當天的優惠:" + reply_block // 回傳優惠
                            }
                        ]
                        break;
                    }
                    // 關鍵字都不在兩張資料表裡,則回傳沒找到訊息
                    else {
                        replyMessage = [{
                            "type": "text",
                            "text": "抱歉,未找到相關資料,請試看看其他日期"
                        }]
                    }
                }
            }
        }

    }


    //回送 Line Bot 訊息給使用者
    function sendReplyMessage(CHANNEL_ACCESS_TOKEN, replyToken, replyMessage) {
        var url = "https://api.line.me/v2/bot/message/reply";
        UrlFetchApp.fetch(url, {
            "headers": {
                "Content-Type": "application/json; charset=UTF-8",
                "Authorization": "Bearer " + CHANNEL_ACCESS_TOKEN,
            },
            "method": "post",
            "payload": JSON.stringify({
                "replyToken": replyToken,
                "messages": replyMessage,
            }),
        });
    }
}

我沒有實際跑一次測試,但他的流程會是這樣:

  1. 先確認關鍵字是否在第一張資料表內( 我用藝文當第一張 ),如果有則回傳,並跳出迴圈
    ( 就不再搜尋第二張資料表 )
  2. 如果不在第一張資料表內,再檢索第二張資料表有沒有關鍵字相符的活動,有的話則回傳
  3. 兩個資料表都沒找到時則回傳「未找到」訊息

趕時間所以我是用巢狀 if 寫,如果有多張資料表要找還是用回圈會更有效率。

我沒看到你的 Google Sheet,但如果你希望使用者傳 YYYYMMDD 就能同時顯示「藝文」、「優惠」兩張資料表的內容,可以濃縮在一個工作表就好:

YYYYMMDD 藝文 優惠
20210521 我愛你 單身者半價
20210814 情人節 情侶打到骨折!

這樣關鍵字在第一欄,而藝文、優惠分別在二、三欄,只需跑一次回圈就好,並將 reply_message 改成:

var sheet_block = sheet_1.getRange(2,x).getValue(); // 這裡是藝文欄位的資料
var sheet_block_2 = sheet_1.getRange(3,x).getValue(); // 這是優惠的
reply_message = [{
    "type":"text",
    "text":"找到了!當天活動:"+sheet_block
},
{
    "type":"text",
    "text":"當天優惠則為:"+sheet_block_2
}]

reply_message 是個陣列,可以塞好幾個 JSON 內容( 不要加到五個以上 )這樣機器人會傳兩個文字訊息,分別是藝文和活動的資料。

不知道過這麼久你還需不需要 XD 如果有問題歡迎回覆~

Tung_H iT邦新手 5 級 ‧ 2022-05-31 20:59:57 檢舉

大大,可以麻煩您指點一下嗎?因我跟樓主使用一樣的程式碼,目前我嘗試想讓使用者查詢完資料後,可以將想備註的訊息,回填到Google Sheets 試算表中這筆資料的最後一列!麻煩大大提點一下,謝謝!

我要發表回答

立即登入回答