This repository has been archived by the owner on Dec 7, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
chatbot.rb
136 lines (107 loc) · 4.29 KB
/
chatbot.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module Chatbot
def self.handle_response(response, platform)
if response.blank? || !response.key?(:object) || !response.key?(:entry)
return
end
if response[:object] == "page"
response[:entry].each do |entry|
entry[:messaging].each do |messaging_event|
# the facebook ID of the person sending you the message
sender_id = messaging_event["sender"]["id"]
# find or initialize user session
session = UserSession.find_or_create_by(platform: platform, facebook_user_id: sender_id)
# user sent a message
if messaging_event.key?("message") && messaging_event["message"].key?("text")
CustomLogger.log("Message received", namespace: "Messenger") do |logger|
logger.add(messaging_event["message"]["text"])
handle_text_message(messaging_event["message"]["text"], session)
end
# user clicked a button
elsif messaging_event.key?("postback")
# in off topic context
if (off_topic = session.off_topic).present?
session.update_attributes(off_topic: nil)
if messaging_event["postback"]["payload"] == "yes"
off_topic.perform!(session)
else
# repeat former question
handle_node(session.node_id, session)
end
#regular tree node
else
handle_node(messaging_event["postback"]["payload"], session)
end
end
end
end
end
end
private
def self.handle_text_message(message_text, session)
platform = session.platform
# assign last node id or identify root node
parent_id = session.node_id || platform.tree.root_node_id
# in off topic context with confirmation pending
if session.off_topic_id.present?
off_topic = OffTopic.find(session.off_topic_id)
Facebook::Api::send_buttons(session, off_topic.confirmation, [{'title': 'yes', 'payload': 'yes'}, {'title': 'no', 'payload': 'no'}])
return
# consider free text if not opening message
elsif session.node_id.present?
# compare free text input with button labels and try to match
string_match = false
platform.tree.edges_originating_from(parent_id).each do |edge|
if edge.parent['label'].downcase == message_text.downcase
parent_id = edge['target']
string_match = true
break
end
end
# check for matching off topic
if string_match == false
puts DateTime.now.to_s
off_topic_id, probability = Classifier::FastText::predict(message_text, platform.language_code)
puts DateTime.now.to_s
if probability > platform.threshold
off_topic = OffTopic.find(off_topic_id)
if off_topic.confirmation.present?
session.update_attributes(off_topic: off_topic)
Facebook::Api::send_buttons(session, off_topic.confirmation, [{'title': 'yes', 'payload': 'yes'}, {'title': 'no', 'payload': 'no'}])
else
off_topic.perform!(session)
end
return
end
end
end
handle_node(parent_id, session)
end
def self.handle_node(node_id, session)
platform = session.platform
# update user session with current node
session.update_attributes(node_id: node_id.to_i)
parent = platform.tree.get_node_by_id(node_id)
while true do
edges = platform.tree.edges_originating_from(parent['id'])
# skip nodes with single edges because there is nothing to decide
if edges.size == 1
Facebook::Api::send_message(session, "#{parent['label']}: #{edges[0].parent['label']}")
parent = platform.tree.get_node_by_id(edges[0]['target'])
else
break
end
end
if edges.size > 1
options = []
edges.each do |edge|
options.push({'title': edge.parent['label'], 'payload': edge['target']})
end
Facebook::Api::send_buttons(session, parent['label'], options)
else
# leaf node, here goes the action hook
Facebook::Api::send_message(session, parent['label'])
# call external service API here (optional)
#ExternalService::Api::perform_action_hook(node_id, session)
end
end
end