JavaScriptProgramming Language

สร้าง Chatbot ด้วย AI Studio โดย Gemini ร่วมกับ Line Messaging API

เมื่อเรามีโจทย์ว่าเราต้องสร้าง Chatbot ผ่านแอปพลิเคชันยอดนิยมในบ้านเราอย่าง Line Messaging API กัน เบื้องต้นก็เหนื่อยกับการทำ Data และต้องมาทำ RAG (Retrieval Augmented Generative AI) ก็ต้องยอมรับว่า Chatbot เป็นเครื่องมือสำคัญในการให้บริการลูกค้า หรือผู้ใช้บริการของเรา และด้วยการใช้ LINE Developers ร่วมกับ AI Studio เราสามารถสร้างแชทบอทอัจฉริยะที่สามารถโต้ตอบกับผู้ใช้ได้อย่างชาญฉลาด บทความนี้จะพาคุณสร้าง Chatbot ตั้งแต่เริ่มต้นและ Deploy ผ่าน Vercel ได้อย่างง่ายดาย

สิ่งที่ต้องเตรียมในการพัฒนาในรอบนี้คือ

ส่วนของ Line Developers นั้นให้ Login แล้วใช้สิ่งเหล่านี้:

ไปที่ Basic Settings แล้วทำการ Copy ค่า “Channel secret

ต่อมาไปที่ Messaging ให้ไป Copy ค่า “Channel access token” (หากันเองนะครับ)

สรุปส่วนของ LINE Developers

  1. เข้าไปที่ LINE Developers Console ไปจัดการ Line ของเราให้เรียบร้อย
  2. กด Create a new provider ตั้งชื่อสำหรับโปรเจค
  3. สร้าง Messaging API Channel
  4. จดบันทึก Channel Secret และ Channel Access Token เพื่อใช้ในภายหลัง
  5. ตั้งค่า Webhook URL ไปที่ Vercel ของเรา (เดี๋ยวเราจะ Deploy โปรเจคเพื่อใช้ URL นี้)

ส่วนของ Vercel.com

Vercel หลังจากสมัครแล้วอยากให้ติดตั้ง CLI (Command Line Interface) ไว้ใช้รันผ่าน VS Code ที่ https://vercel.com/docs/cli#installing-vercel-cli

เปิด VS Code ขึ้นมาหลังติดตั้งแล้วหรือไปที่ Terminal รันคำสั่ง

npm install -g vercel

ทำการ Login ผ่านบัญชีของ Vercel (ซึ่งเชื่อม Github ไปเถอะ)

vercel login
vercel

เปิด VS code ขึ้นมา กำหนด Folder งานหรือ Project ของเราให้สร้างไฟล์ vercel.json ขึ้นมาที่ Route Folder ของเราเพื่อใส่ข้อมูล

ไฟล์ vercel.json อยู่ที่ root folder มี code ดังนี้:

{
    "version": 2,
    "builds": [
      {
        "src": "index.js",
        "use": "@vercel/node"
      }
    ],
    "routes": [
      {
        "src": "/(.*)",
        "dest": "index.js"
      }
    ]
  }

ส่วนของ AI Studio

AI Studio นี่ต้อง ผูก Payment นะครับก็หาวิธีกันเอาเองนะครับ มันคือ Gemini Advanced นั้นแหละเป็น AI ของ Google ส่วน Ai Studio หากเข้ามาใช้แล้วจะมี Limit ให้เราเลือกใช้ ซึ่งเราจะไปที่หน้าจอนี้ครับ

โมเดลของ Ai Studio จะมีอยู่หลายตัว เราจะทำการ Tune ที่ เมนู Tune a Model ระบบจะมี Template ของ csv สำหรับเตรียม data ให้เราทำ input และ output ใส่เข้าไปเพื่อทำการ import สำหรับปรับแต่ง กระบวนการนี้เรียกว่า RAG (Retrieval Augmented Generation) เป็นการช่วยเพิ่มประสิทธิภาพการทำงานของ Large Language Model (LLM) ใน Generative AI (Gen AI) เหมือนเป็นเทคนิคที่รวม การดึงข้อมูลภายในองค์กร หรือข้อมูลเฉพาะที่เกี่ยวข้องที่เรามี มารวมกับการตอบสนองพื้นฐานแบบเดิมที่สร้างโดย Generative AI ให้มันทำงานเข้าด้วยกัน เพื่อเพิ่มประสิทธิภาพความแม่นยำและความเกี่ยวข้องของข้อมูลเฉพาะกลุ่มที่เราต้องการ

ให้ลองคลิกที่ Tuning Guide จะมี link พาเราไปสร้างไฟล์ csv ส่วนของ input และ output เราต้องใช้เวลาในการ Clean up data และจัดการข้อมูล (ตรงนี้ใช้เวลาในการจัดการที่นาน และให้ข้อมูลออกมาดีๆ กินเวลามากกว่า Develop อีกนะครับ) ส่วนนี้เป็นการทำ csv 2 columns ไปอ่านกันเอง ทำกันเอง ไม่ยากไม่ง่าย

หลังจากใช้ระยะเวลา 2-3 ชาติในการ clean up ข้อมูลของเราให้นำเข้าไป import ผ่าน ai studio แล้วทำการ tune model ใหม่ของเราซะ

แต่ถ้าไม่ก็ใช้ model พื้นๆ ตอบเรื่อยเปื่อย คือ gemini-1.5-flash หรือ gemini-1.5-flash-8b (ตัวเล็กไว ไม่เปลือง Heat) ทำให้ไม่ต้องกลัวว่าจะเกิน Quota ตัดเงินเราเยอะ

ไปเอา API Key ของ AI Studio กัน

การตั้งค่า AI Studio เพื่อเอา API Key มาใช้งาน

  1. เข้าไปที่ AI Studio หรือแพลตฟอร์มที่คุณใช้
  2. สร้าง API Key เพื่อใช้ในการเชื่อมต่อ AI กับ Chatbot

เปิด VS Code ทำการรันคำสั่งนี้ใน Terminal กัน

npm install express line-bot-sdk axios dotenv

คำสั่งข้างต้นเป็นการติดตั้งแพ็กเกจที่จำเป็นสำหรับการพัฒนา LINE Chatbot โดยแต่ละแพ็กเกจมีหน้าที่ดังนี้:

  1. express
    • เป็น เว็บเซิร์ฟเวอร์ Framework สำหรับ Node.js
    • ใช้ในการสร้าง API และจัดการ HTTP request เช่น POST /webhook
    • ตัวอย่างเช่น ใช้ app.post('/webhook', handlerFunction); เพื่อตั้งค่า endpoint สำหรับรับข้อความจาก LINE
  2. line-bot-sdk
    • เป็น LINE Messaging API SDK ที่ใช้เชื่อมต่อกับ LINE Platform
    • ใช้ส่งและรับข้อความจากผู้ใช้ผ่าน LINE Bot
    • ตัวอย่างเช่น client.replyMessage({ replyToken, messages }) ใช้ส่งข้อความตอบกลับไปยังผู้ใช้
  3. axios
    • เป็นไลบรารีสำหรับ ทำ HTTP request
    • ใช้ส่งคำขอไปยัง AI API (เช่น OpenAI, AI Studio) เพื่อขอให้ AI ประมวลผลข้อความที่ได้รับ

สร้างไฟล์ .env ที่ root folder ร่วมกับ vercel.json หรือ ลำดับ Hierarchy เดียวกัน

LINE_CHANNEL_SECRET=your_channel_secret
LINE_ACCESS_TOKEN=your_channel_access_token
AI_API_KEY=your_ai_api_key

ก็ line channel secret ก็ใส่กันเองนะ, line access token ก็เอาของตัวเองมาใส่นะ ai api key ก็จาก ai studio ก็ key ของใครของมันนะ

เปิดไฟล์ index.js ใส่ Code ต่อไปนี้:

const express = require("express");
const { Client } = require("@line/bot-sdk");
const axios = require("axios");
require("dotenv").config();

const app = express();
const PORT = process.env.PORT || 3000;

// ตั้งค่าการเชื่อมต่อ LINE API
const config = {
  channelAccessToken: process.env.LINE_ACCESS_TOKEN,
  channelSecret: process.env.LINE_SECRET,
};

const client = new Client(config);
app.use(express.json());

express → ใช้สำหรับสร้าง Web Server เพื่อรองรับ Webhook ของ LINE Client

@line/bot-sdk → เป็นตัวเชื่อมต่อกับ LINE Messaging

APIaxios → ใช้ส่ง HTTP Request ไปยัง AI API AI Studio

dotenv.config() → โหลดค่าตัวแปรแวดล้อมจาก .env เช่น LINE_ACCESS_TOKEN

ต่อไปเป็นการ Response เรียก รับ ส่ง เพื่อ Connect ไปยัง API ของ Ai Studio ผมแบ่งเป็นสองส่วนคือการรับค่า Text ไปยัง Server เพื่อ Reponse และอีกแบบคือการส่งรูปภาพ แบบ Image ไปยัง Server เพื่อ Response

// ฟังก์ชันเรียก Google AI Studio API (Gemini) แบบข้อความ
async function callGeminiAPI(userMessage) {
  try {
    const response = await axios.post(
      `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${process.env.GEMINI_API_KEY}`,
      {
        contents: [{ parts: [{ text: userMessage }] }],
      },
      { headers: { "Content-Type": "application/json" } }
    );

    const aiResponse = response.data?.candidates?.[0]?.content?.parts?.[0]?.text || "ขออภัย ฉันไม่สามารถตอบคำถามนี้ได้";
    return aiResponse;
  } catch (error) {
    console.error("Error calling Gemini API:", error);
    return "ขออภัยมีการ Request คำสั่งจากผู้ใช้งานมากเกินไปลองใหม่อีกครั้ง";
  }
}

// ฟังก์ชันเรียก Google AI Studio API (Gemini) แบบรูปภาพ
async function callGeminiAPIWithImage(imageBase64) {
  try {
    const response = await axios.post(
      `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${process.env.GEMINI_API_KEY}`,
      {
        contents: [
          { parts: [{ text: "โปรดวิเคราะห์รูปภาพนี้" }] },
          { parts: [{ inline_data: { mime_type: "image/jpeg", data: imageBase64 } }] }
        ],
      },
      { headers: { "Content-Type": "application/json" } }
    );

    const aiResponse = response.data?.candidates?.[0]?.content?.parts?.[0]?.text || "ขออภัย ฉันไม่สามารถวิเคราะห์ภาพนี้ได้";
    return aiResponse;
  } catch (error) {
    console.error("Error calling Gemini API with image:", error);
    return "ขออภัย ฉันไม่สามารถวิเคราะห์ภาพนี้ได้ในขณะนี้";
  }
}

การ Handle รูปภาพจำเป็นต้องใส่คำสั่งนี้ หากไม่ต้องการ ก็ไม่ต้องทำก็ได้

// ฟังก์ชันดาวน์โหลดรูปจาก LINE Server
async function getImageFromLine(messageId) {
  try {
    const url = `https://api-data.line.me/v2/bot/message/${messageId}/content`;
    const response = await axios.get(url, {
      headers: { Authorization: `Bearer ${process.env.LINE_ACCESS_TOKEN}` },
      responseType: "arraybuffer",
    });

    // แปลงรูปเป็น Base64
    const imageBase64 = Buffer.from(response.data, "binary").toString("base64");
    return imageBase64;
  } catch (error) {
    console.error("Error downloading image from LINE:", error);
    return null;
  }
}

เรามาทำ endpoint “webhook” เพื่อใช้งานกับ WebHook ของ Line Messaging API กัน เราจะรันผ่าน vercel ให้พร้อมใช้งาน

// Webhook รับข้อความหรือรูปภาพจาก LINE
app.post("/webhook", async (req, res) => {
  const events = req.body.events;
  for (const event of events) {
    if (event.type === "message") {
      if (event.message.type === "text") {
        const userMessage = event.message.text;
        const aiResponse = await callGeminiAPI(userMessage);

        await client.replyMessage(event.replyToken, {
          type: "text",
          text: aiResponse,
        });

      } else if (event.message.type === "image") {
        const imageBase64 = await getImageFromLine(event.message.id);
        if (!imageBase64) {
          await client.replyMessage(event.replyToken, {
            type: "text",
            text: "ไม่สามารถดาวน์โหลดรูปภาพได้",
          });
          return;
        }

        const aiResponse = await callGeminiAPIWithImage(imageBase64);

        await client.replyMessage(event.replyToken, {
          type: "text",
          text: aiResponse,
        });
      }
    }
  }
  res.sendStatus(200);
});

// Route ทดสอบเซิร์ฟเวอร์
app.get("/", (req, res) => {
  res.send("Hello, this is Line Bot with Gemini AI on Vercel!");
});

module.exports = app;

ภาพรวมของ Code ไฟล์ index.js จะเป็นดังนี้:

const express = require("express");
const { Client } = require("@line/bot-sdk");
const axios = require("axios");
require("dotenv").config();

const app = express();
const PORT = process.env.PORT || 3000;

// ตั้งค่าการเชื่อมต่อ LINE API
const config = {
  channelAccessToken: process.env.LINE_ACCESS_TOKEN,
  channelSecret: process.env.LINE_SECRET,
};

const client = new Client(config);
app.use(express.json());

// ฟังก์ชันเรียก Google AI Studio API (Gemini) แบบข้อความ
async function callGeminiAPI(userMessage) {
  try {
    const response = await axios.post(
      `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${process.env.GEMINI_API_KEY}`,
      {
        contents: [{ parts: [{ text: userMessage }] }],
      },
      { headers: { "Content-Type": "application/json" } }
    );

    const aiResponse = response.data?.candidates?.[0]?.content?.parts?.[0]?.text || "ขออภัย ฉันไม่สามารถตอบคำถามนี้ได้";
    return aiResponse;
  } catch (error) {
    console.error("Error calling Gemini API:", error);
    return "ขออภัยมีการ Request คำสั่งจากผู้ใช้งานมากเกินไปลองใหม่อีกครั้ง";
  }
}

// ฟังก์ชันเรียก Google AI Studio API (Gemini) แบบรูปภาพ
async function callGeminiAPIWithImage(imageBase64) {
  try {
    const response = await axios.post(
      `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${process.env.GEMINI_API_KEY}`,
      {
        contents: [
          { parts: [{ text: "โปรดวิเคราะห์รูปภาพนี้" }] },
          { parts: [{ inline_data: { mime_type: "image/jpeg", data: imageBase64 } }] }
        ],
      },
      { headers: { "Content-Type": "application/json" } }
    );

    const aiResponse = response.data?.candidates?.[0]?.content?.parts?.[0]?.text || "ขออภัย ฉันไม่สามารถวิเคราะห์ภาพนี้ได้";
    return aiResponse;
  } catch (error) {
    console.error("Error calling Gemini API with image:", error);
    return "ขออภัย ฉันไม่สามารถวิเคราะห์ภาพนี้ได้ในขณะนี้";
  }
}

// ฟังก์ชันดาวน์โหลดรูปจาก LINE Server
async function getImageFromLine(messageId) {
  try {
    const url = `https://api-data.line.me/v2/bot/message/${messageId}/content`;
    const response = await axios.get(url, {
      headers: { Authorization: `Bearer ${process.env.LINE_ACCESS_TOKEN}` },
      responseType: "arraybuffer",
    });

    // แปลงรูปเป็น Base64
    const imageBase64 = Buffer.from(response.data, "binary").toString("base64");
    return imageBase64;
  } catch (error) {
    console.error("Error downloading image from LINE:", error);
    return null;
  }
}

// Webhook รับข้อความหรือรูปภาพจาก LINE
app.post("/webhook", async (req, res) => {
  const events = req.body.events;
  for (const event of events) {
    if (event.type === "message") {
      if (event.message.type === "text") {
        const userMessage = event.message.text;
        const aiResponse = await callGeminiAPI(userMessage);

        await client.replyMessage(event.replyToken, {
          type: "text",
          text: aiResponse,
        });

      } else if (event.message.type === "image") {
        const imageBase64 = await getImageFromLine(event.message.id);
        if (!imageBase64) {
          await client.replyMessage(event.replyToken, {
            type: "text",
            text: "ไม่สามารถดาวน์โหลดรูปภาพได้",
          });
          return;
        }

        const aiResponse = await callGeminiAPIWithImage(imageBase64);

        await client.replyMessage(event.replyToken, {
          type: "text",
          text: aiResponse,
        });
      }
    }
  }
  res.sendStatus(200);
});

// Route ทดสอบเซิร์ฟเวอร์
app.get("/", (req, res) => {
  res.send("Hello, this is Line Bot with Gemini AI on Vercel!");
});

module.exports = app;

ตรวจสอบ Project Explorer ของเราว่าวางไฟล์ตามตัวอย่างถูกไหมใน VS Code:

ถ้ามั่นใจว่าพร้อมแล้วให้ไปที่ Terminal ทำการรันคำสั่งสำหรับ ส่ง Program ของเราให้เป็น Production โดยการพิมพ์:

vercel --prod

ตามนี้:

ให้เราไปเช็คว่า Domains ของเราพร้อมใช้ยังไปที่ Vercel (https://vercel.com/)

ตัวอย่างผมจะได้ Domains ว่า deeptext.vercel.app เราจะเอาไปใช้กับ WebHook โดยการใช้ URL ดังนี้: https://deeptext.vercel.app/webhook เอาไปใส่ที่ชอ่ง WebHook ของ Line Messaging API

ทำการ Verifiy ส่วนของ URL ของ WebHook ให้เรียบร้อยถ้า โอเคก็ ลองทดสอบ Chatbot ของเราเลย

จะเห็นว่าเราได้เรียนรู้วิธีสร้าง Chatbot บน LINE โดยใช้ AI Studio และ Deploy ผ่าน Vercel ได้สำเร็จ นี่เป็นพื้นฐานที่สามารถนำไปต่อยอดให้ Chatbot ฉลาดขึ้นได้!

ส่วน Tutorial YouTube รอก่อนนะครับ ยังไม่มีเวลา!, ใครถามหา Source Code! คือจะบอกว่าพิมพ์ให้อธิบายให้ขนาดนี้แล้ว พิมพ์และลองพยายามทำดูปรับดูเองเถอะครับ ไม่ได้ยากอะไรมาก แค่ไอเดีย เวลาทำได้ก็ต่อยอดงานได้เยอะแยะ ทางเว็บเราก็ยินดีด้วย แบ่งมาช่วยรายได้อ่าน เพิ่มวิวให้ช่องให้เว็บก็พอแล้วครับ

ส่วนใครทำไม่ได้ หรือ งง หรืออยากได้มากกว่านี้ จ้างได้ครับ!

Asst. Prof. Banyapon Poolsawas

อาจารย์ประจำสาขาวิชาการออกแบบเชิงโต้ตอบ และการพัฒนาเกม วิทยาลัยครีเอทีฟดีไซน์ & เอ็นเตอร์เทนเมนต์เทคโนโลยี มหาวิทยาลัยธุรกิจบัณฑิตย์ ผู้ก่อตั้ง บริษัท Daydev Co., Ltd, (เดย์เดฟ จำกัด)

Related Articles

Back to top button

Adblock Detected

เราตรวจพบว่าคุณใช้ Adblock บนบราวเซอร์ของคุณ,กรุณาปิดระบบ Adblock ก่อนเข้าอ่าน Content ของเรานะครับ, ถือว่าช่วยเหลือกัน