สร้าง LINE Chatbot x Gemini(Gen AI ที่เก่งที่สุดของ Google) ด้วย Cloud Functions for Firebase
ปี 2023 ถือได้ว่าเป็นการเริ่มต้นยุค AI อย่างแท้จริง จากการที่ OpenAI เปิดตัว ChatGPT แล้วตามติดด้วย Bard จาก Google ที่ใครๆก็หันมาให้ความสนใจในการใช้ประโยชน์เพื่อความสะดวกสบาย เช่น ค้นหาข้อมูล, แต่งบทความ, คำนวณ, แปลความหมาย หรือแม้กระทั่ง เขียนโค้ด
ปีที่ผ่านมา ผมก็มีการหยิบเอา PaLM2 ซึ่งเป็น Large Language Models(LLMs) ที่อยู่เบื้องหลัง Bard มาเชื่อมต่อกับ LINE Chatbot แล้วบอกเล่าวิธีการผ่านบทความมาแล้ว ซึ่งหลายคนที่ได้อ่านคงจะทราบแล้วว่า PaLM2 มันรองรับเฉพาะภาษาอังกฤษ
Get Jirawatee’s stories in your inbox
Join Medium for free to get updates from this writer.
แต่แล้วช่วงปลายปีที่ผ่านมา Google ก็ได้สร้างเซอร์ไพรส์ด้วยการเปิดตัว Gemini ซึ่งเป็น AI Model ที่เก่งที่สุดที่ทีม Google DeepMind เคยมีออกมา โดยมาพร้อมกับการรองรับ 38 ภาษารวมถึงภาษาไทย และที่ล้ำไปกว่าเดิมคือมันสามารถเข้าใจ input ที่หลากหลายมากขึ้นแบบ Multimodal ทั้ง Text, Code, Audio, Image, และ Video
เอาหละ บทความนี้ ผมจะพาทุกคนไปดูความสามารถของ Gemini ผ่านการสร้าง LINE Chatbot ที่เชื่อมต่อกับ Gemini API ทั้งแบบ Text-Only และแบบ Multimodal ด้วย Cloud Functions for Firebase 2nd Gen ตามสไตล์ Zero to Hero ง่ายๆเพียง 5 ขั้นตอนกัน
1. สร้าง Provider และ Channel
ใครที่ยังไม่เคยสร้าง Provider และ Channel สำหรับ LINE Chatbot มาก่อน ก็ให้อ่านบทความปฐมบทด้านล่างนี้ แต่ใครที่คุ้นเคยอยู่แล้วให้ข้ามขั้นตอนนี้ไปได้เลย
2. ติดตั้ง Cloud Functions for Firebase
ใครที่ยังไม่เคยพัฒนาโปรแกรมด้วย Cloud Functions for Firebase มาก่อน ก็ให้อ่านบทความด้านล่างนี้(โดยเฉพาะข้อ 2) แต่สำหรับคนที่คุ้นเคยแล้วให้ข้ามโลด
3. สร้าง Webhook สำหรับ LINE Chatbot
3.1 สร้าง Module สำหรับการเรียกใช้ Messaging API
ในตัวอย่างนี้ผมจะใช้ axios มาเป็นตัวช่วยในการสร้าง request ซึ่งจะต้องทำการติดตั้ง dependency ตัวนี้ก่อน โดยให้เปิด command line แล้วเข้าไปที่ /functions จากนั้นใช้คำสั่ง
npm install axios --saveถัดไปให้สร้างไฟล์ /functions/.env แล้วให้ไป copy ค่า Channel Access Token ของ Messaging API Channel ใน LINE Developers console จากข้อ 1 มาระบุ
CHANNEL_ACCESS_TOKEN=YOUR-CHANNEL-ACCESS-TOKENและเพื่อโค้ดที่สั้น เป็นระเบียบ เราจะแยกฟังก์ชันสำหรับการเรียกใช้ Messaging API ออกมาเป็น module โดยภายในจะมีฟังก์ชัน
getImageBinary()สำหรับการดึง binary ของภาพที่ผู้ใช้ส่งผ่าน LINEreply()สำหรับการตอบข้อความกลับหาผู้ใช้
ขั้นตอนนี้ให้สร้างไฟล์ /functions/utils/line.js แล้วให้ copy โค้ดด้านล่างนี้ไปวาง
const axios = require("axios");
const LINE_HEADER = {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.CHANNEL_ACCESS_TOKEN}`
};
const getImageBinary = async (messageId) => {
const originalImage = await axios({
method: "get",
headers: LINE_HEADER,
url: `https://api-data.line.me/v2/bot/message/${messageId}/content`,
responseType: "arraybuffer"
})
return originalImage.data;
}
const reply = (token, payload) => {
return axios({
method: "post",
url: "https://api.line.me/v2/bot/message/reply",
headers: LINE_HEADER,
data: { replyToken: token, messages: payload }
});
};
module.exports = { getImageBinary, reply };3.2 สร้างและเชื่อมต่อ Webhook กับ Messaging API Channel
ให้เปิดไฟล์ /functions/index.js แล้วให้ copy โค้ดด้านล่างนี้ไปแทนที่โค้ดเดิม เพื่อเตรียมรับ Webhook event ประเภท text และ image จาก LINE
const {onRequest} = require("firebase-functions/v2/https");
const line = require("./utils/line");
exports.webhook = onRequest(async (req, res) => {
if (req.method === "POST") {
const events = req.body.events;
for (const event of events) {
switch (event.type) {
case "message":
if (event.message.type === "text") {
}
if (event.message.type === "image") {
}
break;
}
}
}
res.send(req.method);
});แล้วก็ให้เปิด command line ขึ้นมาอีกครั้ง และให้แน่ใจว่าเราอยู่ที่ functions/ จากนั้นใช้คำสั่งด้านล่างนี้เพื่อ deploy ตัว webhook ของเราขึ้น production
firebase deploy --only functionsเมื่อ deploy เสร็จเรียบร้อยเราจะเห็น Webhook URL โผล่อยู่ใน command line เลย ก็ให้เรา copy มา หรือกรณีที่ไม่พบก็ให้เข้าไปที่ Firebase console เลือกโปรเจคที่เราสร้างไว้ แล้วเลือกเมนู Build > Functions จะเจอชื่อฟังก์ชันและ Webhook URL ที่นั่น
เมื่อได้ Webhook URL มาอย่างสมใจปองแล้ว ก็เอา URL นี้ไปอัพเดทที่ Messaging API Channel ใน LINE Developers console ตามที่ได้สร้างไว้ในข้อที่ 1 และให้มั่นใจว่าได้เปิดใช้ Use webhook ด้วยแล้ว
4. สร้าง API Key ใน Google AI Studio
ขั้นตอนนี้เราจะพาทุกคนไปสร้าง API key สำหรับการใช้งาน Gemini API กัน โดยเริ่มจากคลิกลิงค์ https://aistudio.google.com/app/api-keys แล้วให้กดปุ่ม Create API key ที่มุมขวา จากนั้นจะพบทางเลือกที่ให้เรากดสร้าง API key ด้วยการสร้างโปรเจคใหม่ หรือ จะเลือกโปรเจคที่มีอยู่แล้วใน Google Cloud ก็ได้(ถ้ามี) ซึ่งเมื่อสร้างเสร็จ เราก็จะได้ API key มา
จากนั้นให้เราเพิ่มตัวแปร API_KEY ในไฟล์ /functions/.env แล้วให้เอา API key ระบุลงไปแบบนี้
CHANNEL_ACCESS_TOKEN=YOUR-CHANNEL-ACCESS-TOKEN
API_KEY=YOUR-API-KEY5. เชื่อมต่อ LINE Chatbot เข้ากับ Gemini API
5.1 สร้าง Module สำหรับการเรียกใช้ Gemini API
สำหรับ module ที่เราจะสร้างจะแบ่งการทำงานออกเป็น 3 ฟังก์ชันดังนี้
textOnly()สร้างเนื้อหาจาก input ที่เป็น text เหมาะกับการโต้ตอบรายครั้ง และไม่จำเป็นต้องมีความต่อเนื่อง แนวๆถามมาตอบไปmultimodal()สร้างเนื้อหาจาก input ที่เป็น text และ image เหมาะกับการโต้ตอบแบบรายครั้ง ที่ต้องการให้ output สื่อถึงความสัมพันธ์กับภาพ โดยภาพจะรองรับทั้ง PNG, JPEG, WebP, HEIC, HEIF และยังสามารถแนบภาพได้สูงสุด 16 ภาพ ใน 1 request (Google แนะนำว่าแนบภาพเดียวจะได้ผลลัพธ์ที่ตรงกว่า)chat()สร้างเนื้อหาจาก input ที่เป็น text เหมาะกับการโต้ตอบที่ต่อเนื่องกัน(multi-turn conversation) โดยเราสามารถเก็บประวัติการสนทนาเพื่อให้ AI เรียนรู้ในการสร้างเนื้อหาที่ต่อเนื่องในการตอบครั้งถัดไปได้ ซึ่งประวัติการสนทนาจะอยู่ในรูปแบบของ array ที่จะเก็บการโต้ตอบของ user และ model ตามตัวอย่างด้านล่างนี้
history: [
{
role: "user",
parts: [{ text: "สวัสดีค่ะ" }],
},
{
role: "model",
parts: [{ text: "สวัสดีครับ ผมชื่อตี๋, ผู้เชี่ยวชาญเกี่ยวกับ LINE API ที่ช่วยตอบคำถามให้กับคุณครับ" }],
}
]เมื่อได้ทราบถึง concept ของทั้ง 3 ฟังก์ชันแล้ว ถัดไปเราจะมาลงมือกัน เริ่มจากติดตั้ง GoogleGenerativeAI ซึ่งเป็น dependency สำหรับใช้งาน Gemini API โดยให้เปิด command line แล้วเข้าไปที่ /functions จากนั้นใช้คำสั่ง
npm install @google/genai --saveและเพื่อโค้ดไม่ยาวจนเกินไป เราจะแยกฟังก์ชันทั้ง 3 ออกมาเป็น module โดยให้สร้างไฟล์ /functions/utils/gemini.js แล้วให้ copy โค้ดด้านล่างนี้ไปวาง
const { GoogleGenAI } = require("@google/genai");
const ai = new GoogleGenAI({ apiKey: `${process.env.API_KEY}` });
const textOnly = async (prompt) => {
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: prompt,
});
return response.text;
};
const multimodal = async (imageBinary) => {
const contents = [
{
inlineData: {
data: Buffer.from(imageBinary, "binary").toString("base64"),
mimeType: "image/png"
}
},
{ text: "ช่วยบรรยายภาพนี้ให้หน่อย" }
];
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: contents
});
return response.text;
};
const chat = async (prompt) => {
const chat = ai.chats.create({
model: "gemini-2.5-flash",
history: [
{
role: "user",
parts: [{ text: "สวัสดีจ้า" }],
},
{
role: "model",
parts: [{ text: "สวัสดีครับ ผมชื่อตี๋ ผมเป็นผู้เชี่ยวชาญเกี่ยวกับ LINE API ที่ช่วยตอบคำถามและแบ่งปันความรู้ให้กับชุมขนนักพัฒนา" }],
},
{
role: "user",
parts: [{ text: "ปัจจุบันมี LINE API อะไรบ้างที่ใช้งานได้ในประเทศไทย" }],
},
{
role: "model",
parts: [{ text: "ปัจจุบันมีทั้ง Messaging API, LIFF, LINE Login, LINE Beacon, LINE Pay, และ LINE MINI App ที่สามารถใช้งานในไทยได้ครับ" }],
},
]
});
const response = await chat.sendMessage({
message: prompt,
});
return response.text;
};
module.exports = { textOnly, multimodal, chat };เสร็จแล้วก็ให้เราไปอัพเดทโค้ดในไฟล์ /functions/index.js เพื่อดึงเอา module ของ gemini มาใช้งาน
const {onRequest} = require("firebase-functions/v2/https");
const line = require("./utils/line");
const gemini = require("./utils/gemini");5.2 การใช้งาน textOnly()
ในไฟล์ /functions/index.js ให้เพิ่มโค้ดภายในส่วนที่ตรวจสอบเงื่อนไขว่าเป็นข้อความ text ตามนี้
if (event.message.type === "text") {
const msg = await gemini.textOnly(event.message.text);
await line.reply(event.replyToken, [{ type: "text", text: msg }]);
break;
}จากนั้นก็ deploy ผ่าน command line ด้วยคำสั่ง
firebase deploy --only functionsเสร็จแล้วก็มาดูผลทดสอบกัน…
5.3 การใช้งาน multimodal()
ในไฟล์ /functions/index.js ให้เพิ่มโค้ดภายในส่วนที่ตรวจสอบเงื่อนไขว่าเป็นข้อความ image ตามนี้
if (event.message.type === "image") {
const imageBinary = await line.getImageBinary(event.message.id);
const msg = await gemini.multimodal(imageBinary);
await line.reply(event.replyToken, [{ type: "text", text: msg }]);
break;
}จากนั้นก็ deploy ผ่าน command line ด้วยคำสั่ง
firebase deploy --only functionsการทดสอบนี้ ผมจะแบ่ง prompt ออกเป็น 3 แบบ โดยเรียงลำดับตามผลลัพธ์จากซ้ายไปขวา ซึ่งเนื้อหาที่ Gemini ส่งออกมามันน่าทึ่งมากๆ (AI มันเห็นสิ่งเดียวกับที่เราเห็นเลย)
- ช่วยบรรยายภาพนี้ให้หน่อย
- ช่วยแต่งนิทานจากภาพนี้ให้หน่อย
- ช่วยหาคำตอบของภาพนี้ให้หน่อย
5.4 การใช้งาน chat()
ในไฟล์ /functions/index.js ให้เพิ่มโค้ดภายในส่วนที่ตรวจสอบเงื่อนไขว่าเป็นข้อความ text ตามนี้
if (event.message.type === "text") {
const msg = await gemini.chat(event.message.text);
await line.reply(event.replyToken, [{ type: "text", text: msg }]);
break;
}จากนั้นก็ deploy ผ่าน command line ด้วยคำสั่ง
firebase deploy --only functionsผลทดสอบคือมันสามารถสวมบทเป็นเรา ตาม context ที่เราเตรียมไว้ และตอบคำถามเกี่ยวกับ LINE API ได้ดีเลย ซึ่งในอนาคต ถ้าใครจะต่อยอดก็เก็บบทสนทนาและเพิ่มเข้าไปใน history: [] ก่อนจะส่งให้มันสร้างเนื้อหาถัดๆไป ตัว AI มันก็จะเข้าใจบริบททั้งหมดที่คุยกันมาก่อนหน้าได้ แล้วตอบเนื้อหาที่แม่นยำมากยิ่งขึ้น
การตั้งค่าความปลอดภัย
เบื้องหลังเนื้อหาที่ Gemini สร้างขึ้นมาแต่ละครั้งนั้น จะมีการกรองเนื้อหาที่ไม่เหมาะสมอยู่ด้วย โดยจะแบ่งออกเป็น 4 หมวดหมู่
- Harassment: เนื้อหาเกี่ยวกับการล่วงละเมิด
- Hate speech: เนื้อหาที่แสดงถึงความเกลียดชัง
- Sexually explicit: เนื้อหาที่ไม่เหมาะสมทางเพศ
- Dangerous: เนื้อหาที่ส่งเสริมการกระทำที่เป็นอันตราย
ซึ่งค่าเริ่มต้นของการกรองเนื้อหาทั้ง 4 หมวดหมูจะเป็น BLOCK_MEDIUM_AND_ABOVE หรือจะกรองเอาเนื้อหาที่เสี่ยงจะเข้าข่ายระดับกลางถึงสูงออก โดยระดับของการกรองที่เราสามารถปรับได้ก็จะมีด้วยกัน 4 ระดับ
- BLOCK_NONE: ไม่กรองเนื้อหาใดๆ
- BLOCK_ONLY_HIGH: กรองเนื้อหาที่เสี่ยงสูงออกเท่านั้น
- BLOCK_MEDIUM_AND_ABOVE: กรองเนื้อหาที่เสี่ยงปานกลางถึงสูงออก
- BLOCK_LOW_AND_ABOVE: กรองเนื้อหาที่เสี่ยงต่ำถึงสูงออก
ซึ่งจากที่ได้ทดลองใช้งาน multimodal() ไปเรื่อยๆผมพบว่ามีภาพนึงมันถูก block ซึ่งก็งงว่ามันสุ่มเสี่ยงตรงไหน 55
ผมจึงลองตั้งค่าความปลอดภัยให้ Gemini โดยสร้าง array ของ safetySettings ในทั้ง 4 หมวดหมู แล้วตั้งค่าให้กรองเนื้อหาที่เสี่ยงสูงออกเท่านั้น
const safetySettings = [
{
category: "HARM_CATEGORY_HARASSMENT",
threshold: "BLOCK_ONLY_HIGH"
},
{
category: "HARM_CATEGORY_HATE_SPEECH",
threshold: "BLOCK_ONLY_HIGH"
},
{
category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
threshold: "BLOCK_ONLY_HIGH"
},
{
category: "HARM_CATEGORY_DANGEROUS_CONTENT",
threshold: "BLOCK_ONLY_HIGH"
}
];และเพิ่ม safetySettings เข้าไปตอน generateContent()
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: contents,
config: { safetySettings: safetySettings }
});ทดสอบกับ prompt “บอกหน่อยว่าซ้ายหรือขวาคือสุนัข” แล้วผลลัพธ์ก็ออกมาจนได้
สรุป
การเชื่อมต่อ LINE Chatbot กับ Gemini API ด้วย Cloud Functions for Firebase 2nd Gen สำหรับผมนั้นก็เรียกว่าง่ายมากๆ เพราะโค้ดกระชับและตรงไปตรงมา โดย source code ทั้งหมดผมเอาขึ้น GitHub ไว้ให้แล้ว ใครไม่อยากเขียนเองก็ clone มาเล่นกันได้เลย
Gemini-1.5-Flash-8b ที่เราได้ใช้กันในบทความนี้ มันเก่งจริงๆ นี่ขนาดเป็นโมเดลที่ Google บอกว่าสำหรับใช้งานทั่วไปนะ ปี 2024 นี้จะมีโมเดล Gemini Ultra ที่เก่งกว่าสำหรับงานที่ซับซ้อนกว่า แถมมีการขิงผลการทดสอบที่ชนะ GPT-4 แทบทุกแง่มุม ซึ่งคาดว่าน่าจะเปิดตัวในงาน Google I/O ปีนี้ จะโหดขนาดไหนรอติดตามชมกัน
สุดท้ายนี้หวังว่าตัวอย่างการสร้าง LINE Chatbot x Gemini API ในบทความนี้ ทั้งแบบ Text-Only และ Multimodal จะทำให้ผู้อ่านเห็นภาพและเห็นโอกาสในการนำไปประยุกต์ใช้กับ Use case ของตัวเอง ซึ่งผมจะรอชมผลงานจากทุกคน แล้วพบกันใหม่บทความหน้าครับ










