From 2c55fde7b2d1aad6899241d0708aae85e1eca569 Mon Sep 17 00:00:00 2001 From: Ahmad Faizal B H Date: Fri, 27 Mar 2020 06:32:16 +0000 Subject: [PATCH 1/2] Add botframework webhook --- django_chatbot/__init__.py | 2 +- django_chatbot/handler.py | 68 ++++++------- django_chatbot/models.py | 2 +- .../{views.py => views/__init__.py} | 6 +- django_chatbot/views/botframework.py | 98 +++++++++++++++++++ 5 files changed, 137 insertions(+), 39 deletions(-) rename django_chatbot/{views.py => views/__init__.py} (92%) create mode 100644 django_chatbot/views/botframework.py diff --git a/django_chatbot/__init__.py b/django_chatbot/__init__.py index cd0685a..9ca62ca 100644 --- a/django_chatbot/__init__.py +++ b/django_chatbot/__init__.py @@ -1,7 +1,7 @@ from .chatbot import chat -VERSION = (0, 0, 1) +VERSION = (0, 0, 2) __version__ = '.'.join(map(str, VERSION)) default_app_config = 'django.chatbot.apps.DjangoChatBotConfig' diff --git a/django_chatbot/handler.py b/django_chatbot/handler.py index f9b057a..b4482aa 100644 --- a/django_chatbot/handler.py +++ b/django_chatbot/handler.py @@ -5,24 +5,24 @@ class UserMemory: - def __init__(self, senderID, *args, **kwargs): - self.senderID = senderID + def __init__(self, sender_id, *args, **kwargs): + self.sender_id = sender_id self.update(*args, **kwargs) def __getitem__(self, key): try: - return Memory.objects.get(sender__messengerSenderID=self.senderID, + return Memory.objects.get(sender__sender_id=self.sender_id, key__iexact=key).value except Memory.DoesNotExist: raise KeyError(key) def __setitem__(self, key, val): try: - memory = Memory.objects.get(sender__messengerSenderID=self.senderID, key__iexact=key) + memory = Memory.objects.get(sender__sender_id=self.sender_id, key__iexact=key) memory.value = val Memory.save() except Memory.DoesNotExist: - sender = Sender.objects.get(messengerSenderID=self.senderID) + sender = Sender.objects.get(sender_id=self.sender_id) Memory.objects.create(sender=sender, key=key.lower(), value=val) def update(self, *args, **kwargs): @@ -31,26 +31,26 @@ def update(self, *args, **kwargs): def __delitem__(self, key): try: - return Memory.objects.get(sender__messengerSenderID=self.senderID, key=key).delete() + return Memory.objects.get(sender__sender_id=self.sender_id, key=key).delete() except Memory.DoesNotExist: raise KeyError(key) def __contains__(self, key): - return Memory.objects.filter(sender__messengerSenderID=self.senderID, key=key) + return Memory.objects.filter(sender__sender_id=self.sender_id, key=key) class UserConversation: - def __init__(self, senderID, *args): - self.senderID = senderID + def __init__(self, sender_id, *args): + self.sender_id = sender_id self.extend(list(*args)) def get_sender(self): - return Sender.objects.get(messengerSenderID=self.senderID) + return Sender.objects.get(sender_id=self.sender_id) def get_conversation(self, index): try: - conversations = Conversation.objects.filter(sender__messengerSenderID=self.senderID) + conversations = Conversation.objects.filter(sender__sender_id=self.sender_id) if index < 0: index = -index - 1 conversations = conversations.order_by('-id') @@ -92,7 +92,7 @@ def pop(self): raise IndexError("pop from empty list") def __contains__(self, message): - return Conversation.objects.filter(sender__messengerSenderID=self.senderID, + return Conversation.objects.filter(sender__sender_id=self.sender_id, message=message) @@ -101,33 +101,33 @@ class UserTopic: def __init__(self, *args, **kwargs): self.update(*args, **kwargs) - def __getitem__(self, senderID): + def __getitem__(self, sender_id): try: - sender = Sender.objects.get(messengerSenderID=senderID) + sender = Sender.objects.get(sender_id=sender_id) except Sender.DoesNotExist: - raise KeyError(senderID) + raise KeyError(sender_id) return sender.topic - def __setitem__(self, senderID, topic): + def __setitem__(self, sender_id, topic): try: - sender = Sender.objects.get(messengerSenderID=senderID) + sender = Sender.objects.get(sender_id=sender_id) sender.topic = topic sender.save() except Sender.DoesNotExist: - Sender.objects.create(messengerSenderID=senderID, topic=topic) + Sender.objects.create(sender_id=sender_id, topic=topic) def update(self, *args, **kwargs): for k, v in dict(*args, **kwargs).items(): self[k] = v - def __delitem__(self, senderID): + def __delitem__(self, sender_id): try: - return Sender.objects.get(messengerSenderID=senderID).delete() + return Sender.objects.get(sender_id=sender_id).delete() except Sender.DoesNotExist: - raise KeyError(senderID) + raise KeyError(sender_id) - def __contains__(self, senderID): - return Sender.objects.filter(messengerSenderID=senderID).count() > 0 + def __contains__(self, sender_id): + return Sender.objects.filter(sender_id=sender_id).count() > 0 class UserSession: @@ -136,27 +136,27 @@ def __init__(self, object_class, *args, **kwargs): self.objClass = object_class self.update(*args, **kwargs) - def __getitem__(self, senderID): + def __getitem__(self, sender_id): try: - return self.objClass(Sender.objects.get(messengerSenderID=senderID).messengerSenderID) - except:raise KeyError(senderID) + return self.objClass(Sender.objects.get(sender_id=sender_id).sender_id) + except:raise KeyError(sender_id) - def __setitem__(self, senderID, val): - Sender.objects.get_or_create(messengerSenderID=senderID) - self.objClass(senderID, val) + def __setitem__(self, sender_id, val): + Sender.objects.get_or_create(sender_id=sender_id) + self.objClass(sender_id, val) def update(self, *args, **kwargs): for k, v in dict(*args, **kwargs).items(): self[k] = v - def __delitem__(self, senderID): + def __delitem__(self, sender_id): try: - return Sender.objects.get(messengerSenderID=senderID).delete() + return Sender.objects.get(sender_id=sender_id).delete() except: - raise KeyError(senderID) + raise KeyError(sender_id) - def __contains__(self, senderID): - return Sender.objects.filter(messengerSenderID=senderID).count() > 0 + def __contains__(self, sender_id): + return Sender.objects.filter(sender_id=sender_id).count() > 0 class MyChat(Chat): diff --git a/django_chatbot/models.py b/django_chatbot/models.py index c5dd596..0132430 100644 --- a/django_chatbot/models.py +++ b/django_chatbot/models.py @@ -4,7 +4,7 @@ class Sender(models.Model): - messengerSenderID = models.TextField() + sender_id = models.TextField() topic = models.TextField() diff --git a/django_chatbot/views.py b/django_chatbot/views/__init__.py similarity index 92% rename from django_chatbot/views.py rename to django_chatbot/views/__init__.py index 9b8274b..8f66912 100644 --- a/django_chatbot/views.py +++ b/django_chatbot/views/__init__.py @@ -2,8 +2,8 @@ from django.contrib.auth.decorators import login_required from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt -from .chatbot import chat -from .models import Conversation +from ..chatbot import chat +from ..models import Conversation from django.conf import settings @@ -29,7 +29,7 @@ def web_hook(request): result = chat.respond(message, session_id=sender_id) chat.conversation[sender_id].append_bot(result) del chat.attr[sender_id] - msgs = Conversation.objects.filter(sender__messengerSenderID=sender_id) + msgs = Conversation.objects.filter(sender__sender_id=sender_id) if last_message_id: msgs = msgs.filter(id__gt=last_message_id) count = msgs.count() diff --git a/django_chatbot/views/botframework.py b/django_chatbot/views/botframework.py new file mode 100644 index 0000000..e9ca6d7 --- /dev/null +++ b/django_chatbot/views/botframework.py @@ -0,0 +1,98 @@ +from django.shortcuts import render +from django.http import HttpResponse +from django.views.decorators.csrf import csrf_exempt +from background_task import background +from django.conf import settings +from ..chatbot import chat +import requests +import datetime +import json + +def respond(service_url, reply_to_id, from_data, + recipient_data, message, message_type, conversation): + if settings.APP_CLIENT_ID != "": + url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" + data = { + "grant_type": "client_credentials", + "client_id": settings.APP_CLIENT_ID, + "client_secret": settings.APP_CLIENT_SECRET, + "scope": "https://api.botframework.com/.default" + } + response = requests.post(url, data) + response_data = response.json() + headers = { + "Authorization": "%s %s" % (response_data["token_type"], response_data["access_token"]) + } + else: + headers = {} + if service_url[-1] != "/": + service_url += "/" + response_url = service_url + "v3/conversations/%s/activities/%s" % (conversation["id"], reply_to_id) + requests.post( + response_url, + json={ + "type": message_type, + "timestamp": datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f%zZ"), + "from": from_data, + "conversation": conversation, + "recipient": recipient_data, + "text": message, + "replyToId": reply_to_id + }, + headers=headers + ) + + +@background(schedule=1) +def initiate_conversation(data): + conversation_id = data["id"] + message = getattr(settings, "START_MESSAGE", "Welcome to ChatBotAI") + sender_id = data["conversation"]["id"] + chat.start_new_session(sender_id) + chat.conversation[sender_id].append(message) + respond(data["serviceUrl"], + conversation_id, + data["recipient"], + {"id": sender_id}, + message, + "message", + data["conversation"]) + + +@background(schedule=1) +def respond_to_client(data): + conversation_id = data["id"] + message = data["text"] + sender_id = data["conversation"]["id"] + chat.attr[sender_id] = {'match': None, 'pmatch': None, '_quote': False, 'substitute': True} + chat.conversation[sender_id].append(message) + message = message.rstrip(".! \n\t") + result = chat.respond(message, session_id=sender_id) + chat.conversation[sender_id].append(result) + respond( + data["serviceUrl"], + conversation_id, + data["recipient"], + data["from"], + result, + "message", + data["conversation"] + ) + del chat.attr[sender_id] + + +def conversation_handler(request): + data = json.loads(request.body) + # Send text message + if data["type"] == "conversationUpdate": + initiate_conversation(data) + if data["type"] == "message": + respond_to_client(data) + return HttpResponse("It's working") + + +@csrf_exempt +def web_hook(request): + if request.method == "POST": + return conversation_handler(request) + return HttpResponse("Invalid request method") From fa74a3624d6354272a7ad4e75ab41c543a535434 Mon Sep 17 00:00:00 2001 From: Ahmad Faizal B H Date: Fri, 27 Mar 2020 06:32:16 +0000 Subject: [PATCH 2/2] Add botframework webhook --- django_chatbot/__init__.py | 2 +- django_chatbot/handler.py | 68 ++++++------- django_chatbot/models.py | 2 +- .../{views.py => views/__init__.py} | 6 +- django_chatbot/views/botframework.py | 98 +++++++++++++++++++ 5 files changed, 137 insertions(+), 39 deletions(-) rename django_chatbot/{views.py => views/__init__.py} (92%) create mode 100644 django_chatbot/views/botframework.py diff --git a/django_chatbot/__init__.py b/django_chatbot/__init__.py index cd0685a..9ca62ca 100644 --- a/django_chatbot/__init__.py +++ b/django_chatbot/__init__.py @@ -1,7 +1,7 @@ from .chatbot import chat -VERSION = (0, 0, 1) +VERSION = (0, 0, 2) __version__ = '.'.join(map(str, VERSION)) default_app_config = 'django.chatbot.apps.DjangoChatBotConfig' diff --git a/django_chatbot/handler.py b/django_chatbot/handler.py index f9b057a..b4482aa 100644 --- a/django_chatbot/handler.py +++ b/django_chatbot/handler.py @@ -5,24 +5,24 @@ class UserMemory: - def __init__(self, senderID, *args, **kwargs): - self.senderID = senderID + def __init__(self, sender_id, *args, **kwargs): + self.sender_id = sender_id self.update(*args, **kwargs) def __getitem__(self, key): try: - return Memory.objects.get(sender__messengerSenderID=self.senderID, + return Memory.objects.get(sender__sender_id=self.sender_id, key__iexact=key).value except Memory.DoesNotExist: raise KeyError(key) def __setitem__(self, key, val): try: - memory = Memory.objects.get(sender__messengerSenderID=self.senderID, key__iexact=key) + memory = Memory.objects.get(sender__sender_id=self.sender_id, key__iexact=key) memory.value = val Memory.save() except Memory.DoesNotExist: - sender = Sender.objects.get(messengerSenderID=self.senderID) + sender = Sender.objects.get(sender_id=self.sender_id) Memory.objects.create(sender=sender, key=key.lower(), value=val) def update(self, *args, **kwargs): @@ -31,26 +31,26 @@ def update(self, *args, **kwargs): def __delitem__(self, key): try: - return Memory.objects.get(sender__messengerSenderID=self.senderID, key=key).delete() + return Memory.objects.get(sender__sender_id=self.sender_id, key=key).delete() except Memory.DoesNotExist: raise KeyError(key) def __contains__(self, key): - return Memory.objects.filter(sender__messengerSenderID=self.senderID, key=key) + return Memory.objects.filter(sender__sender_id=self.sender_id, key=key) class UserConversation: - def __init__(self, senderID, *args): - self.senderID = senderID + def __init__(self, sender_id, *args): + self.sender_id = sender_id self.extend(list(*args)) def get_sender(self): - return Sender.objects.get(messengerSenderID=self.senderID) + return Sender.objects.get(sender_id=self.sender_id) def get_conversation(self, index): try: - conversations = Conversation.objects.filter(sender__messengerSenderID=self.senderID) + conversations = Conversation.objects.filter(sender__sender_id=self.sender_id) if index < 0: index = -index - 1 conversations = conversations.order_by('-id') @@ -92,7 +92,7 @@ def pop(self): raise IndexError("pop from empty list") def __contains__(self, message): - return Conversation.objects.filter(sender__messengerSenderID=self.senderID, + return Conversation.objects.filter(sender__sender_id=self.sender_id, message=message) @@ -101,33 +101,33 @@ class UserTopic: def __init__(self, *args, **kwargs): self.update(*args, **kwargs) - def __getitem__(self, senderID): + def __getitem__(self, sender_id): try: - sender = Sender.objects.get(messengerSenderID=senderID) + sender = Sender.objects.get(sender_id=sender_id) except Sender.DoesNotExist: - raise KeyError(senderID) + raise KeyError(sender_id) return sender.topic - def __setitem__(self, senderID, topic): + def __setitem__(self, sender_id, topic): try: - sender = Sender.objects.get(messengerSenderID=senderID) + sender = Sender.objects.get(sender_id=sender_id) sender.topic = topic sender.save() except Sender.DoesNotExist: - Sender.objects.create(messengerSenderID=senderID, topic=topic) + Sender.objects.create(sender_id=sender_id, topic=topic) def update(self, *args, **kwargs): for k, v in dict(*args, **kwargs).items(): self[k] = v - def __delitem__(self, senderID): + def __delitem__(self, sender_id): try: - return Sender.objects.get(messengerSenderID=senderID).delete() + return Sender.objects.get(sender_id=sender_id).delete() except Sender.DoesNotExist: - raise KeyError(senderID) + raise KeyError(sender_id) - def __contains__(self, senderID): - return Sender.objects.filter(messengerSenderID=senderID).count() > 0 + def __contains__(self, sender_id): + return Sender.objects.filter(sender_id=sender_id).count() > 0 class UserSession: @@ -136,27 +136,27 @@ def __init__(self, object_class, *args, **kwargs): self.objClass = object_class self.update(*args, **kwargs) - def __getitem__(self, senderID): + def __getitem__(self, sender_id): try: - return self.objClass(Sender.objects.get(messengerSenderID=senderID).messengerSenderID) - except:raise KeyError(senderID) + return self.objClass(Sender.objects.get(sender_id=sender_id).sender_id) + except:raise KeyError(sender_id) - def __setitem__(self, senderID, val): - Sender.objects.get_or_create(messengerSenderID=senderID) - self.objClass(senderID, val) + def __setitem__(self, sender_id, val): + Sender.objects.get_or_create(sender_id=sender_id) + self.objClass(sender_id, val) def update(self, *args, **kwargs): for k, v in dict(*args, **kwargs).items(): self[k] = v - def __delitem__(self, senderID): + def __delitem__(self, sender_id): try: - return Sender.objects.get(messengerSenderID=senderID).delete() + return Sender.objects.get(sender_id=sender_id).delete() except: - raise KeyError(senderID) + raise KeyError(sender_id) - def __contains__(self, senderID): - return Sender.objects.filter(messengerSenderID=senderID).count() > 0 + def __contains__(self, sender_id): + return Sender.objects.filter(sender_id=sender_id).count() > 0 class MyChat(Chat): diff --git a/django_chatbot/models.py b/django_chatbot/models.py index c5dd596..0132430 100644 --- a/django_chatbot/models.py +++ b/django_chatbot/models.py @@ -4,7 +4,7 @@ class Sender(models.Model): - messengerSenderID = models.TextField() + sender_id = models.TextField() topic = models.TextField() diff --git a/django_chatbot/views.py b/django_chatbot/views/__init__.py similarity index 92% rename from django_chatbot/views.py rename to django_chatbot/views/__init__.py index 9b8274b..8f66912 100644 --- a/django_chatbot/views.py +++ b/django_chatbot/views/__init__.py @@ -2,8 +2,8 @@ from django.contrib.auth.decorators import login_required from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt -from .chatbot import chat -from .models import Conversation +from ..chatbot import chat +from ..models import Conversation from django.conf import settings @@ -29,7 +29,7 @@ def web_hook(request): result = chat.respond(message, session_id=sender_id) chat.conversation[sender_id].append_bot(result) del chat.attr[sender_id] - msgs = Conversation.objects.filter(sender__messengerSenderID=sender_id) + msgs = Conversation.objects.filter(sender__sender_id=sender_id) if last_message_id: msgs = msgs.filter(id__gt=last_message_id) count = msgs.count() diff --git a/django_chatbot/views/botframework.py b/django_chatbot/views/botframework.py new file mode 100644 index 0000000..e9ca6d7 --- /dev/null +++ b/django_chatbot/views/botframework.py @@ -0,0 +1,98 @@ +from django.shortcuts import render +from django.http import HttpResponse +from django.views.decorators.csrf import csrf_exempt +from background_task import background +from django.conf import settings +from ..chatbot import chat +import requests +import datetime +import json + +def respond(service_url, reply_to_id, from_data, + recipient_data, message, message_type, conversation): + if settings.APP_CLIENT_ID != "": + url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" + data = { + "grant_type": "client_credentials", + "client_id": settings.APP_CLIENT_ID, + "client_secret": settings.APP_CLIENT_SECRET, + "scope": "https://api.botframework.com/.default" + } + response = requests.post(url, data) + response_data = response.json() + headers = { + "Authorization": "%s %s" % (response_data["token_type"], response_data["access_token"]) + } + else: + headers = {} + if service_url[-1] != "/": + service_url += "/" + response_url = service_url + "v3/conversations/%s/activities/%s" % (conversation["id"], reply_to_id) + requests.post( + response_url, + json={ + "type": message_type, + "timestamp": datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f%zZ"), + "from": from_data, + "conversation": conversation, + "recipient": recipient_data, + "text": message, + "replyToId": reply_to_id + }, + headers=headers + ) + + +@background(schedule=1) +def initiate_conversation(data): + conversation_id = data["id"] + message = getattr(settings, "START_MESSAGE", "Welcome to ChatBotAI") + sender_id = data["conversation"]["id"] + chat.start_new_session(sender_id) + chat.conversation[sender_id].append(message) + respond(data["serviceUrl"], + conversation_id, + data["recipient"], + {"id": sender_id}, + message, + "message", + data["conversation"]) + + +@background(schedule=1) +def respond_to_client(data): + conversation_id = data["id"] + message = data["text"] + sender_id = data["conversation"]["id"] + chat.attr[sender_id] = {'match': None, 'pmatch': None, '_quote': False, 'substitute': True} + chat.conversation[sender_id].append(message) + message = message.rstrip(".! \n\t") + result = chat.respond(message, session_id=sender_id) + chat.conversation[sender_id].append(result) + respond( + data["serviceUrl"], + conversation_id, + data["recipient"], + data["from"], + result, + "message", + data["conversation"] + ) + del chat.attr[sender_id] + + +def conversation_handler(request): + data = json.loads(request.body) + # Send text message + if data["type"] == "conversationUpdate": + initiate_conversation(data) + if data["type"] == "message": + respond_to_client(data) + return HttpResponse("It's working") + + +@csrf_exempt +def web_hook(request): + if request.method == "POST": + return conversation_handler(request) + return HttpResponse("Invalid request method")