Simple chat bot facebook với aiohttp
Chào các bạn, trong bài hôm nay chúng ta sẽ tạo một chat bot đơn giản, đây là chat bot mình sử dụng trên site Taekwondo Tân Phú . Chat bot của chúng ta sẽ sử dụng aiohttp và facebook api để trả lời những câu hỏi với keywords chúng ta viết trong chương trình.
Chuẩn bị
Bạn hãy tạo một virtual env và cài đặt package sau
pip install aiohttp
Coding
Tiếp theo hãy tạo một file app.py với nội dung như sau
import json
import aiohttp
from os import environ
from aiohttp import web
# fanpage token
PAGE_ACCESS_TOKEN = ''
# verify token
VERIFY_TOKEN = ''
class BotControl(web.View):
async def get(self):
query = self.request.rel_url.query
if(query.get('hub.mode') == "subscribe" and query.get("hub.challenge")):
if not query.get("hub.verify_token") == VERIFY_TOKEN:
return web.Response(text='Verification token mismatch', status=403)
return web.Response(text=query.get("hub.challenge"))
return web.Response(text='Forbidden', status=403)
async def post(self):
data = await self.request.json()
if data.get("object") == "page":
await self.send_greeting("Chào bạn. Mình là bot demo của học python.")
for entry in data.get("entry"):
for messaging_event in entry.get("messaging"):
if messaging_event.get("message"):
sender_id = messaging_event["sender"]["id"]
message_text = messaging_event["message"]["text"]
if any(["chào" in message_text.lower(), "hi " in message_text.lower(),
"hello" in message_text.lower(), "có ai" in message_text.lower(),
"có ở đó" in message_text.lower(), "hi" == message_text.lower()]):
await self.send_message(sender_id, "chào đằng ấy :)")
elif any(["bạn tên" in message_text.lower(), "mày tên" in message_text.lower(),
"your name" in message_text.lower(), "cậu tên" in message_text.lower()]):
await self.send_message(sender_id, "mình tên là bot demo aiohttp nha")
elif any(["tác giả" in message_text.lower(), "người viết" in message_text.lower(),
"ai viết" in message_text.lower(), "ba mày" in message_text.lower(), "cha mày" in message_text.lower()
, "bố mày" in message_text.lower(), "tía mày" in message_text.lower()]):
await self.send_message(sender_id, "ahihi bạn vào đây để xem ai là người tạo ra mình nha :3 https://www.hocpython.com")
else:
await self.send_message(sender_id, "Bạn dễ thương gì ấy ơi, ghé https://www.hocpython.com để ủng hộ ba mình nha :3 ")
await self.send_message(sender_id,
"mình nghe ba mình nói nếu mình được 100 like sẽ chia sẻ với các bạn thêm tính năng mới của mình đó :3")
return web.Response(text='ok', status=200)
async def send_greeting(self, message_text):
params = {
"access_token": PAGE_ACCESS_TOKEN
}
headers = {
"Content-Type": "application/json"
}
data = json.dumps({
"setting_type": "greeting",
"greeting": {
"text": message_text
}
})
async with aiohttp.ClientSession() as session:
await session.post("https://graph.facebook.com/v3.0/me/thread_settings", params=params, headers=headers, data=data)
async def send_message(self, sender_id, message_text):
params = {
"access_token": PAGE_ACCESS_TOKEN
}
headers = {
"Content-Type": "application/json"
}
data = json.dumps({
"recipient": {
"id": sender_id
},
"message": {
"text": message_text
}
})
async with aiohttp.ClientSession() as session:
await session.post("https://graph.facebook.com/v3.0/me/messages", params=params, headers=headers, data=data)
routes = [
web.get('/', BotControl, name='verify'),
web.post('/', BotControl, name='webhook'),
]
app = web.Application()
app.add_routes(routes)
if __name__ == '__main__':
web.run_app(app, host='0.0.0.0', port=environ.get("PORT", 9090))
Tất cả các function của bot chúng ta sẽ đặt trong class BotControl(web.View).Trong class này chúng ta sẽ có 2 coroutine chính là get và post, và một số function khác hỗ trợ việc gửi tin nhắn đến facebook. Chúng ta sẽ cùng xem qua một lượt các function
Đầu tiên là async def get(): function này có nhiệm vụ là làm verify callback với facebook, khi bạn thực hiện submit url tới webhook, facebook sẽ yêu cầu verify token trùng với VERIFY_TOKEN trong chat bot để xác nhận đủ quyền thực hiện webhook
async def get(self):
query = self.request.rel_url.query
if(query.get('hub.mode') == "subscribe" and query.get("hub.challenge")):
if not query.get("hub.verify_token") == VERIFY_TOKEN:
return web.Response(text='Verification token mismatch', status=403)
return web.Response(text=query.get("hub.challenge"))
return web.Response(text='Forbidden', status=403)
Tiếp đến là async def post(): function này đảm nhận việc gửi tin nhắn đến người dùng khi có ai đó vào fanpage và gửi tin nhắn đến chat bot. Nếu là người dùng mới hoàn toàn tiếp cận fanpage, chat bot sẽ gửi lời chào đến người dùng. Và khi người dùng nhắn tin hỏi chat bot, nếu đúng các từ khóa đã được lập trình trước, chat bot sẽ trả lời theo ý đã được bạn code
async def post(self):
data = await self.request.json()
if data.get("object") == "page":
await self.send_greeting("Chào bạn. Mình là bot demo của học python.")
for entry in data.get("entry"):
for messaging_event in entry.get("messaging"):
if messaging_event.get("message"):
sender_id = messaging_event["sender"]["id"]
message_text = messaging_event["message"]["text"]
if any(["chào" in message_text.lower(), "hi " in message_text.lower(),
"hello" in message_text.lower(), "có ai" in message_text.lower(),
"có ở đó" in message_text.lower(), "hi" == message_text.lower()]):
await self.send_message(sender_id, "chào đằng ấy :)")
elif any(["bạn tên" in message_text.lower(), "mày tên" in message_text.lower(),
"your name" in message_text.lower(), "cậu tên" in message_text.lower()]):
await self.send_message(sender_id, "mình tên là bot demo aiohttp nha")
elif any(["tác giả" in message_text.lower(), "người viết" in message_text.lower(),
"ai viết" in message_text.lower(), "ba mày" in message_text.lower(), "cha mày" in message_text.lower()
, "bố mày" in message_text.lower(), "tía mày" in message_text.lower()]):
await self.send_message(sender_id, "ahihi bạn vào đây để xem ai là người tạo ra mình nha :3 https://www.hocpython.com")
else:
await self.send_message(sender_id, "Bạn dễ thương gì ấy ơi, ghé https://www.hocpython.com để ủng hộ ba mình nha :3 ")
await self.send_message(sender_id,
"mình nghe ba mình nói nếu mình được 100 like sẽ chia sẻ với các bạn thêm tính năng mới của mình đó :3")
return web.Response(text='ok', status=200)
function async def send_greeting(self, message_text): nhận vào một tham số message_text. message_text chính là lời chào của chat bot khi người dùng mới hoàn toàn bấm mở messenger của fanpage lên
async def send_greeting(self, message_text):
params = {
"access_token": PAGE_ACCESS_TOKEN
}
headers = {
"Content-Type": "application/json"
}
data = json.dumps({
"setting_type": "greeting",
"greeting": {
"text": message_text
}
})
async with aiohttp.ClientSession() as session:
await session.post("https://graph.facebook.com/v3.0/me/thread_settings", params=params, headers=headers, data=data)
function async def send_message(self, sender_id, message_text): function này cũng thực hiện chức năng gửi tin nhắn đến người dùng, nhưng nó nhận vào 2 tham số, sender_id là id của người dùng, và message_text là nội dung mà chat bot sẽ gửi tin nhắn đến người dùng
async def send_message(self, sender_id, message_text):
params = {
"access_token": PAGE_ACCESS_TOKEN
}
headers = {
"Content-Type": "application/json"
}
data = json.dumps({
"recipient": {
"id": sender_id
},
"message": {
"text": message_text
}
})
async with aiohttp.ClientSession() as session:
await session.post("https://graph.facebook.com/v3.0/me/messages", params=params, headers=headers, data=data)
Chúng ta sẽ khai báo routes đến aiohttp với 2 coroutine vừa tạo ở class BotControl như sau
routes = [
web.get('/', BotControl, name='verify'),
web.post('/', BotControl, name='webhook'),
]
Sau đó, chúng ta sẽ khai báo application và add routes vào
app = web.Application()
app.add_routes(routes)
if __name__ == '__main__':
web.run_app(app, host='0.0.0.0', port=environ.get("PORT", 9090)) #1
- Tại dòng này mình lấy port từ enviroment nếu có hoặc không có mình lấy mặc đinh là port 9090
Upload app lên heroku
Để cấu hình app của chúng ta chạy được trên heroku, bạn hãy tạo file requirements.txt với nội dung như sau
aiohttp==3.1.3
gunicorn
Tiếp theo bạn hãy tạo một file mới tên là Procfile với nội dung sau
web: gunicorn app:app --worker-class aiohttp.worker.GunicornWebWorker
Khi bạn dùng gunicorn thì gunicorn sẽ tự run_app, bạn cần phải comment out 2 dòng bên dưới trong file app.py. Nếu bạn vẫn còn để 2 dòng này trong app.py thì gunicorn sẽ không start được
#if __name__ == '__main__':
# web.run_app(app, host='0.0.0.0', port=environ.get("PORT", 9090))
Sau đó submit tất cả lên heroku và thực hiện bước cuối là kết nối với facebook
Kết nối với Facebook
Ở thời điểm hiện tại mình viết bài này, facebook chỉ support chat bot cho fanpage. Chúng ta cần tạo một app cho facebook, app này sẽ hook tới chat bot của chúng ta. Nếu bạn chưa biết cách tạo app, hãy đọc bài hướng dẫn tạo app mới nhất 2018.
Sau khi tạo app cho con chat bot, chúng ta cần add product messenger vào app vừa tạo, từ bên cột trái bạn nhấn vào Products + > Messenger > Setup
Bạn kéo xuống kiếm Token Generation và chọn page cần tích hợp chat bot
Một cửa sổ popup hiện ra yêu cầu bạn cung cấp quyền cho App được tích hợp vào, lúc này chúng ta chưa cần cho facebook review. Bạn chỉ click "Continue as ..." và "Ok" để hoàn tất việc tạo Token
Bạn hãy copy Token này và paste vào PAGE_ACCESS_TOKEN trong app.py
# fanpage token
PAGE_ACCESS_TOKEN = ''
Tiếp tục bạn hãy nhấn vào Setup Webhooks, một cửa sổ mới hiện ra, bạn hãy điền vào như trong hình. Sau đó bạn hãy nhấn Verify and Save
- Callback URL: bạn sẽ nhập vào địa chỉ dẫn tới chat bot của bạn. Lưu ý rằng url chat bot của bạn phải là giao thức https để có thể hoạt động. Nếu bạn cài đặt bot ở heroku thì hãy copy url chat bot của heroku vào đây, hoặc bạn cài chat bot ở vps thì copy url vào đây. Trường hợp của mình là cài đặt chatbot ở heroku nên url sẽ là https://chatbotaiohttp.herokuapp.com/
- Verify Token: Bạn chú ý là đây không phải là Token lấy ở bước trước. Chuỗi token này là chuỗi bạn tự gõ vào. Bạn có thể gõ bằng tay, hoặc vào trang password generator để tạo token hoặc muốn theo cách python như sau. Một điều khác cần lưu ý là verify_token ở đây và trong code chat bot phải giống nhau, nếu không bạn sẽ không verify được
Python 3.6.5 (default, May 11 2018, 04:00:52) [GCC 8.1.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import string >>> from secrets import choice >>> ''.join([choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for letter in range(32)]) 's3Vip8lgh2GEkt60CnmnaZ1SBUYLixlg' >>>
- Subscription Fields: chat bot của chúng ta chỉ xài mặc định là message
Bạn hãy copy Verify Token ở trên vào VERIFY_TOKEN trong app.py
# verify token
VERIFY_TOKEN = ''
Vẫn ở mục Webhooks, bạn hãy tìm đoạn này "Select a page to subscribe your webhook to the page events" vào chọn page mà bạn vừa tạo token ở trên để subscribe fanpage với chat bot. Sau đó upload app.py lên host / heroku và restart lại server. Nếu bước này bạn không upload lên và restart thì bạn sẽ gặp lỗi khi nhấn Verify and Save
Vì hiện tại bạn chưa submission cho facebook review, nên bạn chỉ có thể test chatbot với account của bạn thôi. Bạn hãy chuyển status của app từ public về is developer để test nha
Để có thể submit bot của bạn cho facebook verify bạn hãy theo các bước tại đây. https://developers.facebook.com/docs/messenger-platform/app-review
Bài viết về chat bot facebook với aiohttp đến đây là kết thúc. Mọi ý kiến góp ý của các bạn mình rất hoan nghênh. Các bạn thắc mắc có thể hỏi mình bằng cách comment tại bài viết này hoặc trên group Python Community Viet Nam
Link github: https://github.com/kikyo2006/facebook-chat-bot-aiohttp
** Update: do page Live Streaming on Computer không còn hoạt động nữa, nên mình chuyển bot về fanpage taekwondo Tân Phú
Link page test chat bot: https://www.facebook.com/taekwondotanphu
Không có nhận xét nào