สมัคร apikey Gemini
https://aistudio.google.com/apikey
กิจกรรมที่ 1 ถามตอบ Gemini แบบไม่ต่อเนื่อง
const LINE_TOKEN = 'xxxxx';
const GEMINI_API_KEY = 'xxxxxx';
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent';
function doPost(e) {
const data = JSON.parse(e.postData.contents);
const event = data.events[0];
if (event.type === 'message' && event.message.type === 'text') {
const userText = event.message.text;
const replyToken = event.replyToken;
// Call Gemini API
const payload = {
contents: [{
role: 'user',
parts: [{ text: userText }]
}]
};
const response = UrlFetchApp.fetch(GEMINI_API_URL + '?key=' + GEMINI_API_KEY, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
});
const responseData = JSON.parse(response.getContentText());
let messageText = 'ขอโทษครับ ไม่สามารถตอบได้ตอนนี้';
if (responseData.candidates && responseData.candidates.length > 0) {
messageText = responseData.candidates[0].content.parts[0].text;
}
// Send reply
sendMessage(replyToken, { type: 'text', text: messageText.substring(0, 2000) });
}
}
function sendMessage(replyToken, message) {
const url = 'https://api.line.me/v2/bot/message/reply';
UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + LINE_TOKEN },
payload: JSON.stringify({ replyToken, messages: [message] })
});
}กิจกรรมที่ 2 ถามตอบ Gemini แบบต่อเนื่อง
const LINE_TOKEN = 'xxxxxx';
const GEMINI_API_KEY = 'xxxxx';
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
function doPost(e) {
const data = JSON.parse(e.postData.contents);
const event = data.events[0];
if (event.type === 'message' && event.message.type === 'text') {
const userId = event.source.userId;
const userText = event.message.text;
const replyToken = event.replyToken;
// ดึง history เดิม
const history = getChatHistory(userId);
history.push({ role: 'user', parts: [{ text: userText }] });
// เตรียม payload
const payload = { contents: history };
const response = UrlFetchApp.fetch(GEMINI_API_URL + '?key=' + GEMINI_API_KEY, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
});
const responseData = JSON.parse(response.getContentText());
let messageText = 'ขอโทษครับ ไม่สามารถตอบได้ตอนนี้';
if (responseData.candidates && responseData.candidates.length > 0) {
const messageText = responseData.candidates[0].content.parts[0].text;
// เพิ่มคำตอบของ bot ลงใน history
history.push({ role: 'model', parts: [{ text: messageText }] });
// เก็บ history ใหม่ (จำกัดไม่เกิน 10 รายการ)
saveChatHistory(userId, history.slice(-10));
}
// ส่งข้อความกลับไปยังผู้ใช้
sendMessage(replyToken, { type: 'text', text: messageText.substring(0, 2000) });
}
}
function sendMessage(replyToken, message) {
const url = 'https://api.line.me/v2/bot/message/reply';
UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + LINE_TOKEN },
payload: JSON.stringify({ replyToken, messages: [message] })
});
}
function getChatHistory(userId) {
const props = PropertiesService.getUserProperties();
const key = `history_${userId}`;
const historyJson = props.getProperty(key);
return historyJson ? JSON.parse(historyJson) : [];
}
function saveChatHistory(userId, history) {
const props = PropertiesService.getUserProperties();
const key = `history_${userId}`;
props.setProperty(key, JSON.stringify(history));
}🎯 Use Case 1: ผู้ช่วยตอบคำถามนักเรียนเกี่ยวกับบทเรียน
📌 สถานการณ์:
คุณสร้าง LINE Bot สำหรับนักเรียนชั้น ป.6 ที่ใช้ถามปัญหาคณิตศาสตร์พื้นฐาน เช่น "เศษส่วน", "การหาร", หรือ "การคิดเปอร์เซ็นต์"
🧠 บริบทที่กำหนดเอง:
{ "role": "system", "parts": [{ "text": "คุณคือครูผู้ช่วยสอนคณิตศาสตร์ระดับประถม ให้คำอธิบายง่าย ใช้ตัวอย่างจริง" }] }
👦 นักเรียน:
ครูครับ เศษ 2/5 บวกกับ 1/10 ยังไงครับ
🤖 Bot:
ให้หาค่านิยมร่วมก่อนครับ 5 กับ 10 คูณกันได้ 10
2/5 = 4/10 แล้ว + 1/10 = 5/10 หรือ 1/2 ครับ🎯 Use Case 2: ที่ปรึกษานวัตกรรมการเรียนรู้ให้ครู
📌 สถานการณ์:
ครูในศูนย์การศึกษาพิเศษถามบอทผ่าน LINE ว่าจะจัดกิจกรรมฝึกกล้ามเนื้อมือให้เด็กออทิสติกอย่างไรดี
🧠 บริบทที่กำหนดเอง:
{ "role": "system", "parts": [{ "text": "คุณคือผู้เชี่ยวชาญด้านการจัดกิจกรรมเพื่อพัฒนาทักษะเด็กพิเศษ โดยเฉพาะกล้ามเนื้อมือและสายตา" }] }
👩🏫 ครู:
กิจกรรมแบบไหนที่ช่วยให้เด็กออทิสติกฝึกตา-มือดีครับ
🤖 Bot:
แนะนำกิจกรรมจับคู่ภาพ ตัดกระดาษด้วยกรรไกร เล่นเกมจับลูกบอลหลากสีผ่านท่อใสครับ
กิจกรรมเหล่านี้ช่วยให้เด็กโฟกัสสายตาและใช้มือสัมพันธ์กันได้กิจกรรมที่ 3 ถามตอบ Gemini เข้าใจบริบท
const LINE_TOKEN = 'xxxxxx';
const GEMINI_API_KEY = 'xxxxx';
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
function doPost(e) {
const data = JSON.parse(e.postData.contents);
const event = data.events[0];
if (event.type === 'message' && event.message.type === 'text') {
const userId = event.source.userId;
const userText = event.message.text;
const replyToken = event.replyToken;
// กำหนดบริบทเริ่มต้น เช่น ข้อความที่ให้กับระบบ
let context = getChatHistory(userId);
// ตัวอย่างบริบทที่กำหนดเอง
if (context.length === 0) {
context.push({ role: 'system', parts: [{ text: 'คุณคือผู้ช่วยตอบคำถามที่มีความรู้เกี่ยวกับร้านอาหาร' }] });
}
// เพิ่มข้อความของผู้ใช้ในบริบท
context.push({ role: 'user', parts: [{ text: userText }] });
// ส่งคำขอไปที่ Gemini API
const payload = { contents: context };
const response = UrlFetchApp.fetch(GEMINI_API_URL + '?key=' + GEMINI_API_KEY, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
});
const responseData = JSON.parse(response.getContentText());
let messageText = 'ขอโทษครับ ไม่สามารถตอบได้ตอนนี้';
if (responseData.candidates && responseData.candidates.length > 0) {
messageText = responseData.candidates[0].content.parts[0].text;
}
// เพิ่มคำตอบของบอทลงในบริบท
context.push({ role: 'model', parts: [{ text: messageText }] });
// เก็บบริบทใหม่กลับไปใน properties
saveChatHistory(userId, context);
// ส่งข้อความกลับไปยังผู้ใช้
sendMessage(replyToken, { type: 'text', text: messageText.substring(0, 2000) });
}
}
function sendMessage(replyToken, message) {
const url = 'https://api.line.me/v2/bot/message/reply';
UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + LINE_TOKEN },
payload: JSON.stringify({ replyToken, messages: [message] })
});
}
function getChatHistory(userId) {
const props = PropertiesService.getUserProperties();
const key = `history_${userId}`;
const historyJson = props.getProperty(key);
return historyJson ? JSON.parse(historyJson) : [];
}
function saveChatHistory(userId, history) {
const props = PropertiesService.getUserProperties();
const key = `history_${userId}`;
props.setProperty(key, JSON.stringify(history));
}กิจกรรมที่ 4 ถามตอบ Gemini กำหนดบริบทเอง
const LINE_TOKEN = 'xxxx';
const GEMINI_API_KEY = 'xxxx';
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
function doPost(e) {
const data = JSON.parse(e.postData.contents);
const event = data.events[0];
if (event.type === 'message' && event.message.type === 'text') {
const userText = event.message.text;
const replyToken = event.replyToken;
// กำหนดบริบทที่ต้องการ (ตัวอย่างบริบทที่กำหนดเอง)
const context = [
{ role: 'model', parts: [{ text: 'คุณคือผู้ช่วยตอบคำถามที่มีความรู้เกี่ยวกับร้านอาหาร' }] },
{ role: 'user', parts: [{ text: 'คุณเป็นบอทร้านอาหารชื่อ ครัวคุณป้า เมนูมี: ก๋วยเตี๋ยวต้มยำ(80บาท), ข้าวผัด(60บาท)' }] },
];
// เพิ่มข้อความของผู้ใช้ลงไปในบริบท
context.push({ role: 'user', parts: [{ text: userText }] });
// ส่งคำขอไปที่ Gemini API
const payload = { contents: context };
const response = UrlFetchApp.fetch(GEMINI_API_URL + '?key=' + GEMINI_API_KEY, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
});
const responseData = JSON.parse(response.getContentText());
let messageText = 'ขอโทษครับ ไม่สามารถตอบได้ตอนนี้';
if (responseData.candidates && responseData.candidates.length > 0) {
messageText = responseData.candidates[0].content.parts[0].text;
}
// ส่งข้อความกลับไปยังผู้ใช้
sendMessage(replyToken, { type: 'text', text: messageText.substring(0, 2000) });
}
}
function sendMessage(replyToken, message) {
const url = 'https://api.line.me/v2/bot/message/reply';
UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + LINE_TOKEN },
payload: JSON.stringify({ replyToken, messages: [message] })
});
}กิจกรรมที่ 5 ถามตอบ Gemini วิเคราะห์ภาพ
const LINE_TOKEN = 'xxxx';
const GEMINI_API_KEY = 'xxxx';
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
function doPost(e) {
const data = JSON.parse(e.postData.contents);
const event = data.events[0];
if (event.type === 'message') {
const userId = event.source.userId;
const replyToken = event.replyToken;
const history = getChatHistory(userId);
// รับข้อความจากผู้ใช้
if (event.message.type === 'text') {
const userText = event.message.text;
history.push({ role: 'user', parts: [{ text: userText }] });
// รับรูปภาพจากผู้ใช้
} else if (event.message.type === 'image') {
const imageData = getLineImage(event.message.id);
const base64Image = Utilities.base64Encode(imageData);
history.push({
role: 'user',
parts: [
{ text: 'วิเคราะห์รูปภาพนี้:' },
{ inlineData: { mimeType: 'image/jpeg', data: base64Image } }
]
});
}
// เรียก Gemini API ตรงนี้
const payload = { contents: history, generationConfig: { maxOutputTokens: 2000 } };
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
let botReply = 'ขอโทษครับ ไม่สามารถตอบได้ตอนนี้';
try {
const response = UrlFetchApp.fetch(GEMINI_API_URL + '?key=' + GEMINI_API_KEY, options);
const data = JSON.parse(response.getContentText());
if (data.candidates && data.candidates.length > 0) {
botReply = data.candidates[0].content.parts.map(p => p.text).join('');
}
} catch (err) {
Logger.log('Gemini API Error: ' + err);
botReply = 'เกิดข้อผิดพลาดในการติดต่อ AI';
}
// เก็บและส่งข้อความกลับ
history.push({ role: 'model', parts: [{ text: botReply }] });
saveChatHistory(userId, history.slice(-10));
sendMessage(replyToken, { type: 'text', text: botReply.substring(0, 2000) });
}
}
function sendMessage(replyToken, message) {
const url = 'https://api.line.me/v2/bot/message/reply';
UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + LINE_TOKEN },
payload: JSON.stringify({ replyToken, messages: [message] })
});
}
function getLineImage(messageId) {
const url = `https://api-data.line.me/v2/bot/message/${messageId}/content`;
const options = {
headers: { Authorization: 'Bearer ' + LINE_TOKEN, 'Content-Type': 'application/octet-stream' },
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
if (response.getResponseCode() !== 200) {
throw new Error('ไม่สามารถดึงข้อมูลรูปภาพได้');
}
return response.getBlob().getBytes();
}
function getChatHistory(userId) {
const props = PropertiesService.getUserProperties();
const data = props.getProperty(`history_${userId}`);
return data ? JSON.parse(data) : [];
}
function saveChatHistory(userId, history) {
PropertiesService.getUserProperties().setProperty(`history_${userId}`, JSON.stringify(history));
}ตัวอย่างบันทึกข้อมูลลง google sheet
const SHEET_ID = '1zxl-4z7gqOO92IqM_IYdpKs0FYhN68r3sHMfjoX_fd8'; // Google Sheet ID
logToSheet(state.name, state.phone, state.location);
function logToSheet(name, phone, location) {
const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName('Repairs');
sheet.appendRow([new Date(), name, phone, location]);
}กิจกรรมที่ 6 ตัวอย่างระบบแจ้งซ่อม
const LINE_TOKEN = 'xxxx';
const GEMINI_API_KEY = 'xxxx';
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
const SHEET_ID = 'xxxx'; // Google Sheet ID
function doPost(e) {
const data = JSON.parse(e.postData.contents);
const event = data.events[0];
const userId = event.source.userId;
const replyToken = event.replyToken;
let state = getUserState(userId) || { step: 0 };
if (event.type === 'message') {
if (event.message.type === 'image' && state.step === 0) {
const imageData = getLineImage(event.message.id);
const base64Image = Utilities.base64Encode(imageData);
// วิเคราะห์ก่อน
const analysis = analyzeImage(base64Image);
state.image = base64Image;
state.step = 'wait_confirm_analysis';
saveUserState(userId, state);
// ส่งผลการวิเคราะห์ + Quick Reply
sendMessage(replyToken, {
type: 'text',
text: `ผลการวิเคราะห์ภาพ:\n\n${analysis}\n\nต้องการแจ้งซ่อมหรือไม่?`,
quickReply: {
items: [
{
type: 'action',
action: { type: 'message', label: 'แจ้งซ่อม', text: 'แจ้งซ่อม' }
},
{
type: 'action',
action: { type: 'message', label: 'ไม่แจ้งซ่อม', text: 'ไม่แจ้งซ่อม' }
}
]
}
});
} else if (event.message.type === 'text') {
const text = event.message.text.trim();
// หลังวิเคราะห์เสร็จ รอเลือกว่าจะซ่อมหรือไม่
if (state.step === 'wait_confirm_analysis') {
if (text === 'แจ้งซ่อม') {
state.step = 1;
saveUserState(userId, state);
sendMessage(replyToken, { type: 'text', text: 'กรุณาพิมพ์ชื่อผู้แจ้ง:' });
} else if (text === 'ไม่แจ้งซ่อม') {
sendMessage(replyToken, { type: 'text', text: 'ยกเลิกการแจ้งซ่อม ✅' });
clearUserState(userId);
} else {
sendMessage(replyToken, { type: 'text', text: 'กรุณาเลือก "แจ้งซ่อม" หรือ "ไม่แจ้งซ่อม"' });
}
} else if (state.step === 1) {
state.name = text;
state.step = 2;
saveUserState(userId, state);
sendMessage(replyToken, { type: 'text', text: 'กรุณาพิมพ์เบอร์โทร:' });
} else if (state.step === 2) {
state.phone = text;
state.step = 3;
saveUserState(userId, state);
sendMessage(replyToken, { type: 'text', text: 'กรุณาพิมพ์สถานที่ซ่อม:' });
} else if (state.step === 3) {
state.location = text;
state.step = 4;
saveUserState(userId, state);
const summary =
`📋 สรุปข้อมูลแจ้งซ่อม:\n` +
`ชื่อผู้แจ้ง: ${state.name}\n` +
`เบอร์โทร: ${state.phone}\n` +
`สถานที่: ${state.location}\n\n` +
`พิมพ์ "ยืนยัน" เพื่อบันทึก หรือ "ยกเลิก" เพื่อยกเลิก`;
sendMessage(replyToken, { type: 'text', text: summary });
} else if (state.step === 4) {
if (text === 'ยืนยัน') {
logToSheet(state.name, state.phone, state.location);
sendMessage(replyToken, { type: 'text', text: 'บันทึกการแจ้งซ่อมเรียบร้อย ✅' });
clearUserState(userId);
} else if (text === 'ยกเลิก') {
sendMessage(replyToken, { type: 'text', text: 'ยกเลิกการแจ้งซ่อมแล้ว ❌' });
clearUserState(userId);
} else {
sendMessage(replyToken, { type: 'text', text: 'กรุณาพิมพ์ "ยืนยัน" หรือ "ยกเลิก"' });
}
} else {
sendMessage(replyToken, { type: 'text', text: 'กรุณาส่งภาพเพื่อเริ่มต้นแจ้งซ่อม' });
}
}
}
}
// วิเคราะห์ภาพด้วย Gemini
function analyzeImage(base64Image) {
const instruction = `
คุณเป็นช่างผู้เชี่ยวชาญ
วิเคราะห์ปัญหาจากภาพนี้ บอก:
1. ปัญหาคืออะไร
2. สาเหตุที่เป็นไปได้
3. แนวทางแก้ไขทีละขั้นตอน
`;
const history = [{
role: 'user',
parts: [
{ text: instruction },
{ inlineData: { mimeType: 'image/jpeg', data: base64Image } }
]
}];
const payload = { contents: history, generationConfig: { maxOutputTokens: 1000 } };
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
};
try {
const response = UrlFetchApp.fetch(GEMINI_API_URL + '?key=' + GEMINI_API_KEY, options);
const data = JSON.parse(response.getContentText());
if (data.candidates && data.candidates.length > 0) {
return data.candidates[0].content.parts.map(p => p.text).join('');
}
return 'ไม่สามารถวิเคราะห์ภาพได้';
} catch (err) {
return 'เกิดข้อผิดพลาดในการวิเคราะห์ภาพ';
}
}
// ดึงรูปจาก LINE
function getLineImage(messageId) {
const url = `https://api-data.line.me/v2/bot/message/${messageId}/content`;
const options = {
headers: { Authorization: 'Bearer ' + LINE_TOKEN, 'Content-Type': 'application/octet-stream' }
};
const response = UrlFetchApp.fetch(url, options);
return response.getBlob().getBytes();
}
// ส่งข้อความไป LINE
function sendMessage(replyToken, message) {
UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + LINE_TOKEN },
payload: JSON.stringify({ replyToken, messages: [message] })
});
}
// จัดการ State ผู้ใช้
function getUserState(userId) {
const props = PropertiesService.getUserProperties();
const state = props.getProperty(`state_${userId}`);
return state ? JSON.parse(state) : null;
}
function saveUserState(userId, state) {
PropertiesService.getUserProperties().setProperty(`state_${userId}`, JSON.stringify(state));
}
function clearUserState(userId) {
PropertiesService.getUserProperties().deleteProperty(`state_${userId}`);
}
// บันทึกลง Google Sheets
function logToSheet(name, phone, location) {
const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName('Repairs');
sheet.appendRow([new Date(), name, phone, location]);
}