/*
* Author : James Chou ( wiiai.com ) 簡潔但穩定有力的版本 預覽圖片網址 顯示圖片網址 預覽影片網址 顯示影片網址 還有 flex 和 button
*/
var myWant;
var mySearch;
var uMessage;
var userID;
var userName;
var userPicUrl;
var now;
var xyz;
var oriMessagre;
var userWords;
var isChatGPT
var isToline
var vp;
var aiOutput;
var imageThumbnailUrl = ”;
var imageUrl = ”;
var videoThumbnailUrl = ”;
var videoUrl = ”;
var flex1={
“type”: “bubble”,
“hero”: {
“type”: “image”,
“url”: “https://developers-resource.landpress.line.me/fx/img/01_1_cafe.png”,
“size”: “full”,
“aspectRatio”: “20:13”,
“aspectMode”: “cover”,
“action”: {
“type”: “uri”,
“uri”: “https://line.me/”
}
},
“body”: {
“type”: “box”,
“layout”: “vertical”,
“contents”: [
{
“type”: “text”,
“text”: “最新課程”,
“weight”: “bold”,
“size”: “xl”
},
{
“type”: “box”,
“layout”: “baseline”,
“margin”: “md”,
“contents”: [
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “text”,
“text”: “5.0”,
“size”: “sm”,
“color”: “#999999”,
“margin”: “md”,
“flex”: 0
}
]
},
{
“type”: “box”,
“layout”: “vertical”,
“margin”: “lg”,
“spacing”: “sm”,
“contents”: [
{
“type”: “box”,
“layout”: “baseline”,
“spacing”: “sm”,
“contents”: [
{
“type”: “text”,
“text”: “課程種類”,
“color”: “#aaaaaa”,
“size”: “sm”,
“flex”: 1
},
{
“type”: “text”,
“text”: “LineBot相關”,
“wrap”: true,
“color”: “#666666”,
“size”: “sm”,
“flex”: 5
}
]
},
{
“type”: “box”,
“layout”: “baseline”,
“spacing”: “sm”,
“contents”: [
{
“type”: “text”,
“text”: “主辦”,
“color”: “#aaaaaa”,
“size”: “sm”,
“flex”: 1
},
{
“type”: “text”,
“text”: “愛迪生開發事業有限公司”,
“wrap”: true,
“color”: “#666666”,
“size”: “sm”,
“flex”: 5
}
]
}
]
}
]
},
“footer”: {
“type”: “box”,
“layout”: “vertical”,
“spacing”: “sm”,
“contents”: [
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “message”,
“label”: “課程簡介”,
“text”: “課程簡介”
}
},
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “message”,
“label”: “課程內容”,
“text”: “課程內容”
}
},
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “message”,
“label”: “上課時間地點”,
“text”: “上課時間地點”
}
},
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “message”,
“label”: “交通”,
“text”: “交通”
}
},
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “message”,
“label”: “如何報名”,
“text”: “如何報名”
}
},
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “message”,
“label”: “如何繳費”,
“text”: “如何繳費”
}
},
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “message”,
“label”: “講師”,
“text”: “講師”
}
},
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “message”,
“label”: “曾上課學員”,
“text”: “曾上課學員”
}
}
],
“flex”: 0
}
};
var flex2 = {
“type”: “bubble”,
“hero”: {
“type”: “image”,
“url”: “https://developers-resource.landpress.line.me/fx/img/01_1_cafe.png”,
“size”: “full”,
“aspectRatio”: “20:13”,
“aspectMode”: “cover”,
“action”: {
“type”: “uri”,
“uri”: “https://line.me/”
}
},
“body”: {
“type”: “box”,
“layout”: “vertical”,
“contents”: [
{
“type”: “text”,
“text”: “Brown Cafe”,
“weight”: “bold”,
“size”: “xl”
},
{
“type”: “box”,
“layout”: “baseline”,
“margin”: “md”,
“contents”: [
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gold_star_28.png”
},
{
“type”: “icon”,
“size”: “sm”,
“url”: “https://developers-resource.landpress.line.me/fx/img/review_gray_star_28.png”
},
{
“type”: “text”,
“text”: “4.0”,
“size”: “sm”,
“color”: “#999999”,
“margin”: “md”,
“flex”: 0
}
]
},
{
“type”: “box”,
“layout”: “vertical”,
“margin”: “lg”,
“spacing”: “sm”,
“contents”: [
{
“type”: “box”,
“layout”: “baseline”,
“spacing”: “sm”,
“contents”: [
{
“type”: “text”,
“text”: “Place”,
“color”: “#aaaaaa”,
“size”: “sm”,
“flex”: 1
},
{
“type”: “text”,
“text”: “Flex Tower, 7-7-4 Midori-ku, Tokyo”,
“wrap”: true,
“color”: “#666666”,
“size”: “sm”,
“flex”: 5
}
]
},
{
“type”: “box”,
“layout”: “baseline”,
“spacing”: “sm”,
“contents”: [
{
“type”: “text”,
“text”: “Time”,
“color”: “#aaaaaa”,
“size”: “sm”,
“flex”: 1
},
{
“type”: “text”,
“text”: “10:00 – 23:00”,
“wrap”: true,
“color”: “#666666”,
“size”: “sm”,
“flex”: 5
}
]
}
]
}
]
},
“footer”: {
“type”: “box”,
“layout”: “vertical”,
“spacing”: “sm”,
“contents”: [
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “uri”,
“label”: “CALL”,
“uri”: “https://line.me/”
}
},
{
“type”: “button”,
“style”: “link”,
“height”: “sm”,
“action”: {
“type”: “uri”,
“label”: “WEBSITE”,
“uri”: “https://line.me/”
}
},
{
“type”: “box”,
“layout”: “vertical”,
“contents”: [],
“margin”: “sm”
}
],
“flex”: 0
}
};
//以下是環境變數,就是左方齒輪設定要先填才能代入
const env = {
OPENAI_TOKEN: PropertiesService.getScriptProperties().getProperty(‘OPENAI_TOKEN’),
CHANNEL_ACCESS_TOKEN: PropertiesService.getScriptProperties().getProperty(‘CHANNEL_ACCESS_TOKEN’),
SHEET_URL:PropertiesService.getScriptProperties().getProperty(‘SHEET_URL’),
AI_SET:PropertiesService.getScriptProperties().getProperty(“AI_SET”),
AI_MODEL:PropertiesService.getScriptProperties().getProperty(“AI_MODEL”),
AI_AFTER:PropertiesService.getScriptProperties().getProperty(“AI_AFTER”),
AI_CH:PropertiesService.getScriptProperties().getProperty(“AI_CH”),
CHATBOTNEED:PropertiesService.getScriptProperties().getProperty(“CHATBOTNEED”),
AI_NAME:PropertiesService.getScriptProperties().getProperty(“AI_NAME”)};
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(“工作表1”); // 根據您的情況調整工作表名稱
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(“客戶基本資料”); // 根據您的情況調整工作表名稱
var sheet3 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(“關鍵字”);
var sheet4 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(“AI設定”);
var xcv = env.AI_CH;
// 下面這主程式你就想像成,是使用者輸入時,Line回傳的資料,主要有訊息類別、誰傳的、傳了什麼字、還有一個叫replyToken的參數,這是用來回傳時,要比對的,不然電腦不曉得要回傳到哪.
function doPost(e) {
// LINE Messenging API Token
// 以 JSON 格式解析 User 端傳來的 e 資料
var msg = JSON.parse(e.postData.contents);
// for debugging
Logger.log(msg);
console.log(msg);
// 從接收到的訊息中取出 replyToken 和發送的訊息文字
var replyToken = msg.events[0].replyToken;
var myType = msg.events[0].message.type;
var userMessage;
if (myType !== “text”) {userMessage=”貼圖”;}
else { userMessage = msg.events[0].message.text;}
// 以上的 if 是先判斷傳的是貼圖或文字,只要是文字,機器人才能據以回答,否則一律視為貼圖處理.(因為使用者有可能傳照片、聲音、影片等目前機器人還不能認出的物件)
const user_id = msg.events[0].source.userId;
var event_type = msg.events[0].source.type;
try {
var groupid = msg.events[0].source.groupId;
}
catch{
console.log(“wrong”);
}
switch (event_type) {
case “user”:
var nameurl = “https://api.line.me/v2/bot/profile/” + user_id;
break;
case “group”:
var nameurl = “https://api.line.me/v2/bot/group/” + groupid + “/member/” + user_id;
break;
}
try {
// 呼叫 LINE User Info API,以 user ID 取得該帳號的使用者名稱
var response = UrlFetchApp.fetch(nameurl, {
“method”: “GET”,
“headers”: {
“Authorization”: “Bearer ” + env.CHANNEL_ACCESS_TOKEN,
“Content-Type”: “application/json”
},
});
var namedata = JSON.parse(response);
var reserve_name = namedata.displayName ;
var reserve_userId = namedata.userId;
var reserve_pictureUrl = namedata.pictureUrl;
var reserve_userMessage = userMessage;
oriMessagre=userMessage;
//以上我們最主要的就是取出 replyToken 、 userMessage、user_id、還有頭像的圖片網址
}
catch{
reserve_name = “not avaliable”;
}
if (typeof replyToken === ‘undefined’) {
return;
};
isChatGPT = sheet4.getRange(“B1”).getValue();
isToline = sheet4.getRange(“B2”).getValue();
if (isToline != “yes”) {isChatGPT = “no”;sheet4.getRange(“B1”).setValue(“No”);} //確保 Line既然只記錄不輸出,自然不用ChatGPT了,省錢.
userID = user_id;
userName = reserve_name ;
userPicUrl = reserve_pictureUrl;
userWords = reserve_userMessage;
now = Utilities.formatDate(new Date(), “GMT+8”, “yyyy-MM-dd HH:mm:ss”); //只要是記錄,時間一定要加進來
var current_list_row = sheet1.getLastRow();
sheet1.getRange(current_list_row + 1, 1).setValue(reserve_userId);
sheet1.getRange(current_list_row + 1, 2).setValue(reserve_name);
sheet1.getRange(current_list_row + 1, 3).setValue(reserve_userMessage);
sheet1.getRange(current_list_row + 1, 4).setValue(now);
checkUserExist();
mySearch = userMessage.toLowerCase().trim();
userMessage = userMessage.toLowerCase().trim();
//以下區段是最先執行權
if (userMessage.length < 2 && userMessage != “嗨”) {mySearch = “文字太長或太短”; }
if (userMessage.length > 300 ) {mySearch = “文字太長或太短”; }
//if (userMessage.trim().includes(“緊急呼叫”) && userMessage.trim().length > 5){
// var managerID=”輸入管理員的UserID ” ; message=userName+oriMessagre; sendPushMessage(managerID, message);return;}
if (userMessage.trim()==”最新課程”){replyFlex(replyToken, flex1);return;}
if (userMessage.trim()==”多媒體”){replyFlex(replyToken, flex2);return;}
//最先執行權結束
searchAndFormatResults(userMessage); //這是先用傳統的資料檢索,如果檢索的到,就不用啟動機器人,檢索不到,才啟動機器人
if (!myWant){
uMessage = “”;
}else{
uMessage = myWant;
}
if (uMessage!=””) {myWant=env.AI_NAME+”:\n”+myWant;}
else {
if (isChatGPT.toLowerCase().trim()== “yes” ) {
let resp = GPTturbo(userMessage);
resp = resp.toString();
//checkAndReplaceString(resp); //如果採用語意分析法,這行要恢復,用來確保ai的回答不會錯,若錯了會發訊息給管理員
//searchAgain(resp); //如果要採用 searchAgain 這個就要恢復,但角色設定也要同時修改
myWant = resp; // 如果採用語意分析法,這行要MARK掉
myWant = myWant.replace(/[。.]$/, ”);
myWant = myWant.trim().replace(/[。]/g, ‘ ‘);
myWant = myWant.trim().replace(‘(‘, ‘( ‘);
myWant = myWant.trim().replace(‘[‘, ‘[ ‘);
myWant = myWant.trim().replace(‘)’, ‘) ‘);
myWant = myWant.trim().replace(‘].’, ‘] ‘);
myWant = myWant.trim().replace(‘。’, ‘ ‘);
}
}
//回傳訊息給line 並傳送給使用者
//replyToLine(replyToken, myWant);
//replyToLine(replyToken, myWant); 不能這樣子連傳兩則,因為傳完 replyToken 就失效了.
handleReply(replyToken,myWant);
}
function handleReply(replyToken,myWant) {
// 檢查圖片網址是否有效
if (imageThumbnailUrl.includes(‘http’) && imageUrl.includes(‘http’)) {
replyTextAndImage(replyToken, myWant, imageUrl, imageThumbnailUrl);return;
}
// 如果有影片網址也可以進行檢查
if (videoThumbnailUrl.includes(‘http’) && videoUrl.includes(‘http’)) {
replyTextAndVideo(replyToken, myWant, videoUrl, videoThumbnailUrl);return;
}
replyToLine(replyToken, myWant);
}
function replyToLine(replyToken, myWant) {if (isToline.trim().toLowerCase()== “yes”) {
var payload = {
‘replyToken’: replyToken,
‘messages’: [
{
‘type’: ‘text’,
‘text’: myWant
},
]
};
var options = {
‘method’: ‘post’,
‘headers’: {
‘Content-Type’: ‘application/json’,
‘Authorization’: ‘Bearer ‘ + env.CHANNEL_ACCESS_TOKEN
},
‘payload’: JSON.stringify(payload)
};
UrlFetchApp.fetch(‘https://api.line.me/v2/bot/message/reply’, options);
}
}
function replyImage(replyToken,myWant) {
//var imageUrl = ‘https://wiilands.com/wp-content/uploads/2024/04/512512.jpg’; // 圖片的 URL
//var imageThumbnailUrl = ‘https://wiilands.com/wp-content/uploads/2024/04/512512.jpg’; // 縮圖的 URL
var payload = {
‘replyToken’: replyToken,
‘messages’: [
{
‘type’: ‘text’,
‘text’: myWant
},
{
‘type’: ‘image’,
‘originalContentUrl’: imageUrl,
‘previewImageUrl’: imageThumbnailUrl
}
]
};
var options = {
‘method’: ‘post’,
‘headers’: {
‘Content-Type’: ‘application/json’,
‘Authorization’: ‘Bearer ‘ + env.CHANNEL_ACCESS_TOKEN
},
‘payload’: JSON.stringify(payload)
};
UrlFetchApp.fetch(‘https://api.line.me/v2/bot/message/reply’, options);
}
function replyVideo(replyToken) {
//var videoUrl = ‘https://example.com/path/to/your/video.mp4’; // 影片的 URL
//var videoThumbnailUrl = ‘https://example.com/path/to/your/thumbnail.jpg’; // 影片縮圖的 URL
var payload = {
‘replyToken’: replyToken,
‘messages’: [
{
‘type’: ‘video’,
‘originalContentUrl’: videoUrl,
‘previewImageUrl’: videoThumbnailUrl
}
]
};
var options = {
‘method’: ‘post’,
‘headers’: {
‘Content-Type’: ‘application/json’,
‘Authorization’: ‘Bearer ‘ + env.CHANNEL_ACCESS_TOKEN
},
‘payload’: JSON.stringify(payload)
};
UrlFetchApp.fetch(‘https://api.line.me/v2/bot/message/reply’, options);
}
function replyTextAndImage(replyToken, myWant, imageUrl, imageThumbnailUrl) {
var payload = {
‘replyToken’: replyToken,
‘messages’: [
{
‘type’: ‘text’,
‘text’: myWant
},
{
‘type’: ‘image’,
‘originalContentUrl’: imageUrl,
‘previewImageUrl’: imageThumbnailUrl
}
]
};
var options = {
‘method’: ‘post’,
‘headers’: {
‘Content-Type’: ‘application/json’,
‘Authorization’: ‘Bearer ‘ + env.CHANNEL_ACCESS_TOKEN
},
‘payload’: JSON.stringify(payload)
};
UrlFetchApp.fetch(‘https://api.line.me/v2/bot/message/reply’, options);
}
function replyTextAndVideo(replyToken, myWant, videoUrl, videoThumbnailUrl) {
var payload = {
‘replyToken’: replyToken,
‘messages’: [
{
‘type’: ‘text’,
‘text’: myWant
},
{
‘type’: ‘image’,
‘originalContentUrl’: videoUrl,
‘previewImageUrl’: videoThumbnailUrl
}
]
};
var options = {
‘method’: ‘post’,
‘headers’: {
‘Content-Type’: ‘application/json’,
‘Authorization’: ‘Bearer ‘ + env.CHANNEL_ACCESS_TOKEN
},
‘payload’: JSON.stringify(payload)
};
UrlFetchApp.fetch(‘https://api.line.me/v2/bot/message/reply’, options);
}
function replyFlex(replyToken, flexContents) {
var payload = {
‘replyToken’: replyToken,
‘messages’: [
{
‘type’: ‘flex’,
‘altText’: ‘多媒體訊息’,
‘contents’: flexContents
}
]
};
var options = {
‘method’: ‘post’,
‘headers’: {
‘Content-Type’: ‘application/json’,
‘Authorization’: ‘Bearer ‘ + env.CHANNEL_ACCESS_TOKEN
},
‘payload’: JSON.stringify(payload)
};
UrlFetchApp.fetch(‘https://api.line.me/v2/bot/message/reply’, options);
}
function GPTturbo(prompt, temperature = 0.4, model = env.AI_MODEL) {
//下方的 xyz ,實現了機器人可以記住以往客戶所問的話,最多可以1000字,也實現了機器人對每一位客戶問話的回答風格,但若是採用語意分析法就不能用了
xyz = env.AI_SET;
const MAX_TOKENS = 800;
const TEMPERATURE = 0.4;
const url = “https://api.openai.com/v1/chat/completions”;
const payload = {
model: model,
messages: [
{ role: “system”, content: xyz },
{ role: “user”, content: prompt },
],
temperature: TEMPERATURE,
max_tokens: MAX_TOKENS,
};
const options = {
contentType: “application/json”,
headers: { Authorization: “Bearer ” + env.OPENAI_TOKEN },
payload: JSON.stringify(payload),
};
const res = JSON.parse(UrlFetchApp.fetch(url, options).getContentText());
var asd= res.choices[0].message.content.trim().replace(‘。’,’ \n’);
return res.choices[0].message.content.trim().replace(‘。’,’ \n’);
}
function checkUserExist() {
// 檢查客戶基本資料表中UserID是否存在
var basicDataRange = sheet2.getRange(2, 1, sheet2.getLastRow(), 1);
var basicDataValues = basicDataRange.getValues();
var userExists = false;
for (var i = 0; i < basicDataValues.length; i++) {
if (basicDataValues[i][0] == userID) {
userExists = true;
userRow = i + 2; // 因為範圍是從第二行開始的
break;
}
}
// 如果用戶不存在於客戶基本資料表中,則新增
if (!userExists) {
sheet2.appendRow([userID, userName,userPicUrl,now]);
userRow = sheet2.getLastRow(); // 獲取新添加的行數
} }
function searchAndFormatResults(searchTerm) {
//searchTerm = “地點”;
// 檢查搜索詞的有效性
if ((searchTerm.length < 2 && !/[a-zA-Z]/.test(searchTerm)) || searchTerm.length === 0) {
return “搜索詞至少需要兩個字符(對於中文),或者是英文字符。”;
}
var range = sheet3.getDataRange();
var values = range.getValues();
var textResult = “”;
var matches = [];
// 遍歷每一行
for (var i = 0; i < values.length; i++) {
// 檢查第一列是否包含搜索詞
if (values[i][0].toString().toLowerCase().trim().includes(searchTerm.toLowerCase().trim())) {
matches.push(values[i]);
}
}
// 根據匹配的行數處理輸出
if (matches.length === 1) {
// 只有一行匹配,輸出所有欄位
var row = matches[0];
for (var j = 0; j < row.length; j++) {
if (j === 0) {
var name = row[j].toString().split(‘#’)[0].trim(); // 取出#之前的內容
textResult += appendIfNotEmpty(name);
} else {
textResult += appendIfNotEmpty(row[j]);
}
// 使用正則表達式匹配URL
var urlPattern = /https?:\/\/\S+/;
var match = row[j].match(urlPattern);
if (match) {
if (row[j].includes(‘預覽圖片網址’)) {
imageThumbnailUrl = match[0];
}
if (row[j].includes(‘顯示圖片網址’)) {
imageUrl = match[0];
}
if (row[j].includes(‘預覽影片網址’)) {
videoThumbnailUrl = match[0];
}
if (row[j].includes(‘顯示影片網址’)) {
videoUrl = match[0];
}
}
}
//Logger.log(imageThumbnailUrl+imageUrl);
textResult = textResult.replace(/undefined/g, “”).replace(/\n\n/g, “\n”);
}
else if (matches.length > 1) {
// 多行匹配,只輸出第1欄和包含 http 的欄位
for (var i = 0; i < matches.length; i++) {
var name = matches[i][0].toString().split(‘#’)[0].trim(); // 取出#之前的內容
textResult += appendIfNotEmpty(name) + “\n”;
for (var j = 1; j < matches[i].length; j++) {
if (matches[i][j].toString().includes(“http”)) {
textResult += appendIfNotEmpty(matches[i][j]) + “\n”;
}
}
textResult += “\n”;
}
textResult = “有2個以上結果,請再輸入以下任一個來精確查詢。\n” + textResult.replace(/undefined/g, “”).replace(/\n\n/g, “\n”);
}
// 檢查是否有匹配結果
if (textResult === “”) {
Logger.log(textResult.trim());
} else {
// 日誌輸出匹配結果,或根據需要處理匹配結果
Logger.log(“結果:” + textResult.trim());
myWant = textResult.trim();
// 返回純文本格式的匹配結果
}
}
function searchAgain(searchTerm) {
//searchTerm = “上課地點”;
// 檢查搜索詞的有效性
if ((searchTerm.length < 2 && !/[a-zA-Z]/.test(searchTerm)) || searchTerm.length === 0) {
return “搜索詞至少需要兩個字符(對於中文),或者是英文字符。”;
}
var range = sheet3.getDataRange();
var values = range.getValues();
var textResult = “”;
var matches = [];
// 遍歷每一行
for (var i = 0; i < values.length; i++) {
// 檢查第一列是否包含搜索詞
if (values[i][0].toString().toLowerCase().trim().includes(searchTerm.toLowerCase().trim())) {
matches.push(values[i]);
}
}
// 根據匹配的行數處理輸出
if (matches.length === 1) {
// 只有一行匹配,輸出所有欄位
var row = matches[0];
for (var j = 0; j < row.length; j++) {
if (j === 0) {
var name = row[j].toString().split(‘#’)[0].trim(); // 取出#之前的內容
textResult += appendIfNotEmpty(name);
} else {
textResult += appendIfNotEmpty(row[j]);
}
// 使用正則表達式匹配URL
var urlPattern = /https?:\/\/\S+/;
var match = row[j].match(urlPattern);
if (match) {
if (row[j].includes(‘預覽圖片網址’)) {
imageThumbnailUrl = match[0];
}
if (row[j].includes(‘顯示圖片網址’)) {
imageUrl = match[0];
}
if (row[j].includes(‘預覽影片網址’)) {
videoThumbnailUrl = match[0];
}
if (row[j].includes(‘顯示影片網址’)) {
videoUrl = match[0];
}
}
}
textResult = textResult.replace(/undefined/g, “”).replace(/\n\n/g, “\n”);
}
else if (matches.length > 1) {
// 多行匹配,只輸出第1欄和包含 http 的欄位
for (var i = 0; i < matches.length; i++) {
var name = matches[i][0].toString().split(‘#’)[0].trim(); // 取出#之前的內容
textResult += appendIfNotEmpty(name) + “\n”;
for (var j = 1; j < matches[i].length; j++) {
if (matches[i][j].toString().includes(“http”)) {
textResult += appendIfNotEmpty(matches[i][j]) + “\n”;
}
}
textResult += “\n”;
}
textResult = “有2個以上結果,請再輸入以下任一個來精確查詢。\n” + textResult.replace(/undefined/g, “”).replace(/\n\n/g, “\n”);
}
// 檢查是否有匹配結果
if (textResult === “”) {
Logger.log(textResult.trim());
//myWant= “這問題我會請小編迅速回答您!”
} else {
// 日誌輸出匹配結果,或根據需要處理匹配結果
Logger.log(“結果:” + textResult.trim());
myWant = textResult.trim();
// 返回純文本格式的匹配結果
}
}
function datetimeToUnix(timestampStr) {
// 將日期字符串轉換Date對象
var date = new Date(timestampStr);
// 獲取UNIX時間戳(Date對象的getTime()方法返回毫秒,所以除以1000轉換為秒)
var unixTimestamp = date.getTime() / 1000;
return unixTimestamp;
}
function appendIfNotEmpty(value) {
// 檢查值是否為 undefined 或空字符串(包括空白字符)
if (value !== undefined && value !== null && value.trim() !== ”) {
return value + “\n”;
}
return “”;
}
function getCurrentYear() {
var currentDate = new Date(); // 創建一個 Date 對象,它將被初始化為當前日期和時間
var currentYear = currentDate.getFullYear(); // 使用 getFullYear() 方法獲取當前年份
return currentYear;
}
// 發送 Push Message 的函數
function sendPushMessage(userId, message) {
const url = ‘https://api.line.me/v2/bot/message/push’;
const payload = {
to: userId,
messages: [
{
type: ‘text’,
text: message
}
]
};
const options = {
method: ‘post’,
contentType: ‘application/json’,
headers: {
‘Authorization’: ‘Bearer ‘ + env.CHANNEL_ACCESS_TOKEN
},
payload: JSON.stringify(payload)
};
const response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
}
// 測試發送 Push Message
function testSendPushMessage() {
const userId = ‘請填入您的UserID’; // 替換成接收者的 User ID
const message = ‘Hello from Google Apps Script!’;
sendPushMessage(userId, message);
}
function checkAndReplaceString(inputString) {
//以下這要按您自己的自行修改
const categories = [“課程內容”, “課程講師”, “公司簡介”, “時間地點”, “上課費用”,”如何報名”, “如何繳費”, “交通”, “其他”];
for (let i = 0; i < categories.length; i++) {
if (inputString.includes(categories[i])) {
aiOutput= categories[i];
}
else {aiOutput= “AI設定可能錯誤,不符合任何關鍵字”;userId = ‘請填入您的UserID’;sendPushMessage(userId, aiOutput);}
}
}
function createSheetsAndPopulateData() {
//千萬注意,這只執行一次,否則會把你的設定又重置
var ss = SpreadsheetApp.getActiveSpreadsheet();
// 創建新工作表
var sheets = [“客戶基本資料”, “關鍵字”, “AI設定”];
sheets.forEach(function(sheetName) {
if (!ss.getSheetByName(sheetName)) {
ss.insertSheet(sheetName);
}
});
// 在 “客戶基本資料” 表格上加入資料
var customerSheet = ss.getSheetByName(“客戶基本資料”);
var customerHeaders = [“UserID”, “DisplayName”, “PicURL”, “Time”];
customerSheet.getRange(1, 1, 1, customerHeaders.length).setValues([customerHeaders]);
// 在 “關鍵字” 表格上加入資料
var keywordSheet = ss.getSheetByName(“關鍵字”);
var keywordData = [
[“貼圖”, “若有任何問題,請直接點按手機版 Line 上的功能表”],
[“文字太長或太短”, “若有任何問題,請直接點按手機版 Line 上的功能表”]
];
keywordSheet.getRange(1, 1, keywordData.length, keywordData[0].length).setValues(keywordData);
// 在 “AI設定” 表格上加入資料
var aiSettingSheet = ss.getSheetByName(“AI設定”);
var aiSettingData = [
[“isChatGPT”, “no”],
[“isToLine”, “yes”]
];
aiSettingSheet.getRange(1, 1, aiSettingData.length, aiSettingData[0].length).setValues(aiSettingData);
// 設置指令碼屬性
var scriptProperties = PropertiesService.getScriptProperties();
var properties = {
‘AI_AFTER’: ‘謝謝您’,
‘AI_MODEL’: ‘gpt-4o’,
‘AI_NAME’: ‘小愛機器人’,
‘AI_SET’: ‘預設’,
‘AI_CH’: ‘不用理會’,
‘CHANNEL_ACCESS_TOKEN’: ‘填入你自己的’,
‘OPENAI_TOKEN’: ‘這是選項,若要用,請填入你自己的’,
‘CHATBOTNEED’: ‘不拘’,
‘SHEET_URL’: ‘填入你自己的’
};
scriptProperties.setProperties(properties);
}