DEV Community

Boombright
Boombright

Posted on

สร้าง Chatbot AI ให้พูดเหมือนตัวละครโปรดของคุณบน Discord

ถ้าคุณอยากมีบอทไว้คุยโดยพูดเหมือนตัวละครหรือบุคคลที่คุณชื่นชอบ ไม่ว่าจะเป็นตัวละครสมมติหรือบุคคลที่มีอยู่จริงๆก็ตาม หรือแม้กระทั่งสร้างใหมันพูดเหมือนเป็นตัวคุณเองก็ยังได้

โดยเราจะเริ่มตามขั้นตอนด้านล่างนี้ซึ่่งจะมีรายละเอียดด้านล่างลิสต์นี้อีกที

  1. รวบรวมข้อมูลสำหรับตัวละครคุณ จะใช้เซ็ตข้อมูลที่มีอยู่หรือทำขึ้นมาเองโดยใช้ประโยคสนทนาดิบๆ
  2. ฝึกโมเดลบอทของคุณใน Google Colab และทดสอบใน Hugging Face
  3. สร้างบอทสำหรับโปรแกรม Discord โดยสามารถใช้ Python หรือ JavaScript ก็ได้
  4. ตั้งค่าการอณุญาติให้บอทเพื่อป้องกันไม่ให้ไปสแปมข้อความที่ช่องทางอื่น
  5. โฮสบอทใน Repl.it และให้ทำงานต่อเนื่องโดยใช้ Uptime Robot

เตรียมข้อมูลอย่างไร
ข้อมูลที่เราต้องการจะต้องเป็นรูปแบบของการสนทนา ซึ่งจำเป็นมากสำหรับสร้าง Chatbot ในการตอบโต้ข้อความต่างๆ ยกตัวอย่างตัวละครจาก Rick and Morty หรือ Harry Potter ซึ่งเราหาตัวอย่างบทสนทนาได้จากเว็บไซต์ Kaggle โดยเราต้องการแค่ชื่อตัวละคร(Character name)กับบทสนทนา(dialogue line)

Image description

และถ้าไม่มีข้อมูลบน Kaggle สามารถเช็คได้อีกที่คือ Transcript Wiki
(Note เพิ่มเติม: เว็บไซต์ Transcript Wiki ปิดตัวลงแล้ว)

ฝึกโมเดลของคุณอย่างไร
ซึ่งในที่นี้โมเดลของเราจะเป็นแบบ Generative Pre-trained Transfomer (GPT) ที่เป็นตัวโมเดลภาษาที่นิยมสูงสุดในตอนนี้ โดยเราจะใช้ Microsoft's pre-trained GPT, DialoGPT-small และปรับแต่งเพิมเติมโดยใช้ข้อมูลของเรา โดยขั้นตอนเป็นตามนี้

  1. อัพโหลดไฟล์ไปยัง Google Colab (อย่าลืมปรับ runtime เป็น GPU ด้วยเพื่อความรวดเร็วในการฝึกโมเดล)
  2. เปลี่ยนเซ็ตข้อมูลและเป้าหมายตัวละครในโค้ดตามนี้

Image description

ในขั้นตอนนี้คาดว่าใช้เวลาน้อยกว่าครึ่งชั่วโมงเป็นอย่างมาก ตัวอย่างเช่นเรามีทั้งหมด 700 บรรทัดซึ่งใช้เวลาทั้งหมดไม่ถึง 10 นาทีด้ยซ้ำโดยโมเดลจะถูกเก็บในโฟล์เดอร์ที่ชื่อว่า output-small

แหละหากว่าต้องการโมเดลที่ฉลาดและพูดได้เหมือนจริงมากขึ้น แนะนำให้ใช้โมเดลที่ใหญ่ขึ้นอย่าง DialoGPT-medium หรือ DialoGPT-large ซึ่งขนาาดที่ใหญ่ขึ้นหมายถึงมีพารามิเตอร์ที่เยอะขึ้นเพื่อรองรับข้อมูลที่ซับซ้อนมากขึ้น

และเรายังสามารถฝึกโมเดลเหล่านี้ได้เยอะขึ้นโดยหา num_train_epochs ในโน้ตบุ้คของโค้ดโดยตัวเลขเหล่านั้นคือจำนวนครั้งที่ตัวโมเดลจะถูกเทรนผ่านข้อมูชุดนั้นๆ และแน่นอนว่ายิ่งฝึกตัวโมเดลจะฉลาดมากขึ้น

วิธีโฮสต์ตัวโมเดล
เราจะใช้ Hugging Face และหลักจากสมัครแอคเค้าท์แล้วให้กดที่ New model รับ API token โดยไปที่ Edit profile > API Tokens ซึ่งเราจะใช้ในการสร้างบอทดิสคอดและอย่าลืมใส่แท็กเป็น conversational ในตัวการ์ดของโมเดล(หรือ README.md)

Image description

สร้าง Discord bot อย่างไร
ไปยัง Discord Developer's page สร้างแอพลิเคชั่นขึ้นมาจากนั้นค่อยเพิ่มบอทลงไป และปรับ Text Permissions เป็น Send Messgaes เพราะว่า Chatbot ของเราจะทำหน้าที่แค่ตอบข้อความผู้ใช้เท่านั้น จากนั้นคัดลอก API token ของบอทเพื่อเตรียมใช้ในภายหลัง

สมัครแอคเค้าท์หรือล็อคอินเข้า Repl.it จากนั้นสร้าง Repl ใหม่ขึ้นมาซึ่งสามารถใช้ได้ทั้ง Python และ Node.js ขึ้นอยู่กับความสะดวกของคุณเลย

ก่อนอื่นเริ่มจากนำ API tokens ของ Hugging Face และ Discord มาใส่ในช่อง environment variables และตั้งชื่อว่า HUGGINGFACE_TOKEN และ DISCORD_TOKEN ตามภาพนี้

Image description

จากนั้นสามารถใช้โค้ดตามนี้ได้เลย
Python

# the os module helps us access environment variables
# i.e., our API keys
import os

# these modules are for querying the Hugging Face model
import json
import requests

# the Discord Python API
import discord

# this is my Hugging Face profile link
API_URL = 'https://api-inference.huggingface.co/models/r3dhummingbird/'

class MyClient(discord.Client):
    def __init__(self, model_name):
        # adding intents module to prevent intents error in __init__ method in newer versions of Discord.py
        intents = discord.Intents.default() # Select all the intents in your bot settings as it's easier
        intents.message_content = True
        super().__init__(intents=intents)
        self.api_endpoint = API_URL + model_name
        # retrieve the secret API token from the system environment
        huggingface_token = os.environ['HUGGINGFACE_TOKEN']
        # format the header in our request to Hugging Face
        self.request_headers = {
            'Authorization': 'Bearer {}'.format(huggingface_token)
        }

    def query(self, payload):
        """
        make request to the Hugging Face model API
        """
        data = json.dumps(payload)
        response = requests.request('POST',
                                    self.api_endpoint,
                                    headers=self.request_headers,
                                    data=data)
        ret = json.loads(response.content.decode('utf-8'))
        return ret

    async def on_ready(self):
        # print out information when the bot wakes up
        print('Logged in as')
        print(self.user.name)
        print(self.user.id)
        print('------')
        # send a request to the model without caring about the response
        # just so that the model wakes up and starts loading
        self.query({'inputs': {'text': 'Hello!'}})

    async def on_message(self, message):
        """
        this function is called whenever the bot sees a message in a channel
        """
        # ignore the message if it comes from the bot itself
        if message.author.id == self.user.id:
            return

        # form query payload with the content of the message
        payload = {'inputs': {'text': message.content}}

        # while the bot is waiting on a response from the model
        # set the its status as typing for user-friendliness
        async with message.channel.typing():
          response = self.query(payload)
        bot_response = response.get('generated_text', None)

        # we may get ill-formed response if the model hasn't fully loaded
        # or has timed out
        if not bot_response:
            if 'error' in response:
                bot_response = '`Error: {}`'.format(response['error'])
            else:
                bot_response = 'Hmm... something is not right.'

        # send the model's response to the Discord channel
        await message.channel.send(bot_response)

def main():
    # DialoGPT-medium-joshua is my model name
    client = MyClient('DialoGPT-medium-joshua')
    client.run(os.environ['DISCORD_TOKEN'])

if __name__ == '__main__':
  main()
Enter fullscreen mode Exit fullscreen mode

JS script

// discord.js import
const Discord = require('discord.js');
// node-fetch for making HTTP requests
const fetch = require('node-fetch');

// initialize client
const client = new Discord.Client();
// my model URL
API_URL = 'https://api-inference.huggingface.co/models/r3dhummingbird/DialoGPT-medium-joshua';

// log out some info
client.on('ready', () => {
    console.log(`Logged in as ${client.user.tag}!`);
});

// when the bot receives a message
// need async message because we are making HTTP requests
client.on('message', async message => {
    // ignore messages from the bot itself
    if (message.author.bot) {
        return;
    }
    // form the payload
    const payload = {
        inputs: {
            text: message.content
        }
    };
    // form the request headers with Hugging Face API key
    const headers = {
        'Authorization': 'Bearer ' + process.env.HUGGINGFACE_TOKEN
    };

    // set status to typing
    message.channel.startTyping();
    // query the server
    const response = await fetch(API_URL, {
        method: 'post',
        body: JSON.stringify(payload),
        headers: headers
    });
    const data = await response.json();
    let botResponse = '';
    if (data.hasOwnProperty('generated_text')) {
        botResponse = data.generated_text;
    } else if (data.hasOwnProperty('error')) { // error condition
        botResponse = data.error;
    }
    // stop typing
    message.channel.stopTyping();
    // send message to channel as a reply
    message.reply(botResponse);
})

client.login(process.env.DISCORD_TOKEN);
Enter fullscreen mode Exit fullscreen mode

เพิ่มเติมสำหรับคนนที่ใช้ JS เนื่องจากว่าเวอร์ชั่นไม่เข้ากันระหว่าง Repl.it's node กับ NPM เราจำเป็นต้องระบุเวอร์ชั่นที่เก่ากกว่าของ Discord API ใน package.json ตามนี้

"dependencies": {
    "discord.js": "^12.5.3",
}
Enter fullscreen mode Exit fullscreen mode

และนี่คือตัวอย่างการใช้งานครับ

Image description

ทำให้บอททำงานตลอดเวลา
ส่วนสุดท้ายนี่เพราะว่าบอทเหล่านี้จะหยุดทำงานถ้าเราปิดการทำงานของ Repl ซึ่งวิธีแก้คือตั้งเว็บเซิฟเวอร์สำหรับเก็บโค้ดของบิทโดยใช้ Uptime Robot และบันทึกเซิฟเวอร์ Discord ของเราไว้ทำให้ทำงานตลอดเวลา

Image description

สรุป
แชทบอทเหล่านี้ประโยชน์ส่วนใหญ่คือใช้สร้างความบันเทิงผ่านการพิมพ์ และเราสามารถดัดแปลงให้บอทพวกนี้เลียนแบบตัวละครตัวไหนก็ได้ที่เราอยากขอแค่มีประโยคบทสนทนาที่เพียงพอที่จะฝึกโมเดลบอทพวกนี้ได้

Reference:
https://www.freecodecamp.org/news/discord-ai-chatbot/

Top comments (0)