user-simulator 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- metamorphic/__init__.py +9 -0
- metamorphic/results.py +62 -0
- metamorphic/rule_utils.py +482 -0
- metamorphic/rules.py +231 -0
- metamorphic/tests.py +83 -0
- metamorphic/text_comparison_utils.py +31 -0
- technologies/__init__.py +0 -0
- technologies/chatbot_connectors.py +567 -0
- technologies/chatbots.py +80 -0
- technologies/taskyto.py +110 -0
- user_sim/__init__.py +15 -0
- user_sim/cli/sensei_chat.py +1 -1
- user_sim/core/role_structure.py +1 -1
- user_sim/handlers/pdf_parser_module.py +1 -1
- user_sim/utils/register_management.py +1 -1
- {user_simulator-0.1.1.dist-info → user_simulator-0.1.3.dist-info}/METADATA +1 -1
- {user_simulator-0.1.1.dist-info → user_simulator-0.1.3.dist-info}/RECORD +21 -11
- user_simulator-0.1.3.dist-info/top_level.txt +3 -0
- user_simulator-0.1.1.dist-info/top_level.txt +0 -1
- {user_simulator-0.1.1.dist-info → user_simulator-0.1.3.dist-info}/WHEEL +0 -0
- {user_simulator-0.1.1.dist-info → user_simulator-0.1.3.dist-info}/entry_points.txt +0 -0
- {user_simulator-0.1.1.dist-info → user_simulator-0.1.3.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,567 @@
|
|
1
|
+
import json
|
2
|
+
import uuid
|
3
|
+
import yaml
|
4
|
+
import requests
|
5
|
+
from user_sim.utils.url_management import get_content
|
6
|
+
from user_sim.utils.config import errors
|
7
|
+
import logging
|
8
|
+
from user_sim.utils.exceptions import *
|
9
|
+
|
10
|
+
logger = logging.getLogger('Info Logger')
|
11
|
+
|
12
|
+
###################################################
|
13
|
+
# THE CONNECTORS NEED HEAVY REFACTORING TO JUST
|
14
|
+
# ONE OR TWO CLASSES
|
15
|
+
|
16
|
+
class Chatbot:
|
17
|
+
def __init__(self, connector):
|
18
|
+
self.fallback = 'I do not understand you'
|
19
|
+
|
20
|
+
self.connector_args = connector
|
21
|
+
self.config = self.connector_args.get("config")
|
22
|
+
self.payload = self.connector_args.get("payload", {})
|
23
|
+
|
24
|
+
self.api_url = self.config.get("api_url", "")
|
25
|
+
self.headers = self.config.get("headers", {})
|
26
|
+
self.timeout = self.config.get("timeout", 0)
|
27
|
+
self.request_key = self.config.get("request_key", "")
|
28
|
+
self.response_key = self.config.get("response_key", "")
|
29
|
+
|
30
|
+
|
31
|
+
def execute_with_input(self, user_msg):
|
32
|
+
"""Returns a pair [bool, str] in which the first element is True if the chatbot returned normally,
|
33
|
+
and the second is the message.
|
34
|
+
Otherwise, False means that there is an error in the chatbot."""
|
35
|
+
self.parse_message_to_payload(user_msg)
|
36
|
+
|
37
|
+
response = requests.post(self.api_url, headers=self.headers, json=self.payload, timeout=self.timeout)
|
38
|
+
|
39
|
+
try:
|
40
|
+
if response.status_code == 200:
|
41
|
+
response_json = response.json()
|
42
|
+
# response_dict = json.loads(response.text)
|
43
|
+
responses = response_json[self.response_key]
|
44
|
+
if isinstance(responses, list):
|
45
|
+
all_responses = get_content('\n'.join(responses))
|
46
|
+
else:
|
47
|
+
all_responses = get_content(responses)
|
48
|
+
return True, all_responses
|
49
|
+
else:
|
50
|
+
# There is an error, but it is an internal error
|
51
|
+
logger = logging.getLogger('Info Logger')
|
52
|
+
logger.error(f"Server error {response.status_code}")
|
53
|
+
errors.append({response.status_code: f"Couldn't get response from the server"})
|
54
|
+
return False, f"Something went wrong. Status Code: {response.status_code}"
|
55
|
+
|
56
|
+
except requests.exceptions.JSONDecodeError as e:
|
57
|
+
logger = logging.getLogger('Info Logger')
|
58
|
+
logger.error(f"Couldn't get response from the server: {e}")
|
59
|
+
return False, 'chatbot internal error'
|
60
|
+
except requests.Timeout:
|
61
|
+
logger = logging.getLogger('Info Logger')
|
62
|
+
logger.error(f"No response was received from the server in less than {self.timeout}")
|
63
|
+
errors.append({504: f"No response was received from the server in less than {self.timeout}"})
|
64
|
+
return False, 'timeout'
|
65
|
+
|
66
|
+
def parse_message_to_payload(self, message):
|
67
|
+
|
68
|
+
def pmtp(rk):
|
69
|
+
if "." in rk:
|
70
|
+
keys = rk.split('.')
|
71
|
+
ref = self.payload
|
72
|
+
for key in keys[:-1]:
|
73
|
+
if key not in ref or not isinstance(ref[key], dict):
|
74
|
+
ref[key] = {}
|
75
|
+
ref = ref[key]
|
76
|
+
ref[keys[-1]] = message
|
77
|
+
self.payload = ref
|
78
|
+
else:
|
79
|
+
self.payload[rk] = message
|
80
|
+
|
81
|
+
if isinstance(self.request_key, list):
|
82
|
+
for rk in self.request_key:
|
83
|
+
pmtp(rk)
|
84
|
+
else:
|
85
|
+
pmtp(self.request_key)
|
86
|
+
|
87
|
+
def parse_keys(self, structure, message, msg_type):
|
88
|
+
|
89
|
+
def pmtp(ks):
|
90
|
+
if "." in ks:
|
91
|
+
keys = ks.split('.')
|
92
|
+
ref = structure
|
93
|
+
for key in keys[:-1]:
|
94
|
+
if key not in ref or not isinstance(ref[key], dict):
|
95
|
+
ref[key] = {}
|
96
|
+
ref = ref[key]
|
97
|
+
if msg_type == "payload":
|
98
|
+
ref[keys[-1]] = message
|
99
|
+
self.payload = ref
|
100
|
+
elif msg_type == "response":
|
101
|
+
self.response_key = ref
|
102
|
+
else:
|
103
|
+
if msg_type == "payload":
|
104
|
+
self.payload[ks] = message
|
105
|
+
|
106
|
+
if msg_type == "payload":
|
107
|
+
key_strings = self.request_key
|
108
|
+
elif msg_type == "response":
|
109
|
+
key_strings = self.response_key
|
110
|
+
else:
|
111
|
+
raise "invalid message type."
|
112
|
+
|
113
|
+
if isinstance(key_strings, list):
|
114
|
+
for key_string in key_strings:
|
115
|
+
pmtp(key_string)
|
116
|
+
else:
|
117
|
+
pmtp(key_strings)
|
118
|
+
|
119
|
+
@staticmethod
|
120
|
+
def get_connector_args(connector_path):
|
121
|
+
if isinstance(connector_path, str):
|
122
|
+
with open(connector_path, 'r', encoding='UTF-8') as f:
|
123
|
+
connector_args = yaml.safe_load(f)
|
124
|
+
return connector_args
|
125
|
+
elif isinstance(connector_path, dict):
|
126
|
+
return connector_path
|
127
|
+
else:
|
128
|
+
raise InvalidItemType("Connector item is not a string (path) or a dictionary (yaml content).")
|
129
|
+
|
130
|
+
|
131
|
+
##############################################################################################################
|
132
|
+
# RASA
|
133
|
+
class ChatbotRasa(Chatbot):
|
134
|
+
def __init__(self, connector):
|
135
|
+
Chatbot.__init__(self, connector)
|
136
|
+
# self.connector_args = self.get_connector_args(connector)
|
137
|
+
# self.api_url = self.connector_args["api_url"]
|
138
|
+
self.id = None
|
139
|
+
# self.api_url = self.config.get("api_url", "")
|
140
|
+
|
141
|
+
|
142
|
+
def execute_with_input(self, user_msg):
|
143
|
+
if self.id is None:
|
144
|
+
self.id = str(uuid.uuid4())
|
145
|
+
|
146
|
+
new_data = {
|
147
|
+
"sender": self.id,
|
148
|
+
"message": user_msg
|
149
|
+
}
|
150
|
+
post_response = requests.post(self.api_url, json=new_data)
|
151
|
+
post_response_json = post_response.json()
|
152
|
+
if len(post_response_json) > 0:
|
153
|
+
message = '\n'.join([r.get('text') for r in post_response_json])
|
154
|
+
return True, message
|
155
|
+
else:
|
156
|
+
return True, ''
|
157
|
+
|
158
|
+
|
159
|
+
##############################################################################################################
|
160
|
+
# 1million bot chatbots
|
161
|
+
class ChatbotMillionBot(Chatbot):
|
162
|
+
def __init__(self, connector):
|
163
|
+
Chatbot.__init__(self, connector)
|
164
|
+
self.connector_args = self.get_connector_args(connector)
|
165
|
+
self.headers = {}
|
166
|
+
self.payload = {}
|
167
|
+
self.api_url = ""
|
168
|
+
self.id = None
|
169
|
+
|
170
|
+
self.reset_url = None
|
171
|
+
self.reset_payload = None
|
172
|
+
|
173
|
+
self.init_chatbot(self.connector_args['payload'],
|
174
|
+
self.connector_args['timeout'])
|
175
|
+
|
176
|
+
|
177
|
+
|
178
|
+
def init_chatbot(self, payload, timeout):
|
179
|
+
first_api_url = "https://api.1millionbot.com/api/public/users"
|
180
|
+
first_payload = payload
|
181
|
+
first_header = {
|
182
|
+
"Content-Type": "application/json",
|
183
|
+
"Authorization": "API-KEY 60553d58c41f5dfa095b34b5"
|
184
|
+
}
|
185
|
+
first_response = requests.post(first_api_url, headers=first_header, json=first_payload, timeout=timeout)
|
186
|
+
first_response = first_response.json()
|
187
|
+
|
188
|
+
second_payload = {
|
189
|
+
"bot": "60a3be81f9a6b98f7659a6f9",
|
190
|
+
"user": first_response["user"]["_id"],
|
191
|
+
"language": "es",
|
192
|
+
"integration": "web",
|
193
|
+
"gdpr": True
|
194
|
+
}
|
195
|
+
second_header = {
|
196
|
+
"Content-Type": "application/json",
|
197
|
+
"Authorization": "60a3bee2e3987316fed3218f"}
|
198
|
+
second_api_url = "https://api.1millionbot.com/api/public/conversations"
|
199
|
+
second_response = requests.post(second_api_url, headers=second_header, json=second_payload, timeout=timeout)
|
200
|
+
second_response = second_response.json()
|
201
|
+
|
202
|
+
third_payload = {
|
203
|
+
"bot": "60a3be81f9a6b98f7659a6f9",
|
204
|
+
"sender": first_response["user"]["_id"],
|
205
|
+
"conversation": second_response["conversation"]["_id"],
|
206
|
+
"sender_type": "User",
|
207
|
+
"language": "es",
|
208
|
+
"message": {
|
209
|
+
"text": "con quien hablo?"
|
210
|
+
}
|
211
|
+
}
|
212
|
+
third_api_url = "https://api.1millionbot.com/api/public/messages"
|
213
|
+
self.api_url = third_api_url
|
214
|
+
self.headers = second_header
|
215
|
+
self.payload = third_payload
|
216
|
+
self.timeout = timeout
|
217
|
+
|
218
|
+
# Always generate a new ID for the conversation
|
219
|
+
#import uuid
|
220
|
+
#unique_id = uuid.uuid4()
|
221
|
+
#conversation_id = unique_id.hex
|
222
|
+
|
223
|
+
# Randomly replace a letter in the conversation_id with a hexadecimal digit
|
224
|
+
#import random
|
225
|
+
#import string
|
226
|
+
#conversation_id = list(conversation_id)
|
227
|
+
#conversation_id[random.randint(0, len(conversation_id)-1)] = random.choice(string.hexdigits)
|
228
|
+
#conversation_id = ''.join(conversation_id)
|
229
|
+
|
230
|
+
|
231
|
+
# self.reset_url = "https://api.1millionbot.com/api/public/live/status"
|
232
|
+
# self.reset_payload = {"bot": bot_id,
|
233
|
+
# "conversation": conversation_id,
|
234
|
+
# "status": {
|
235
|
+
# "origin": url,
|
236
|
+
# "online": False,
|
237
|
+
# "typing": False,
|
238
|
+
# "deleted": True,
|
239
|
+
# "attended": {},
|
240
|
+
# "userName": "UAM/UMU"}
|
241
|
+
#
|
242
|
+
# }
|
243
|
+
|
244
|
+
|
245
|
+
|
246
|
+
def execute_with_input(self, user_msg):
|
247
|
+
|
248
|
+
self.payload['message']["text"] = user_msg
|
249
|
+
timeout = self.timeout
|
250
|
+
try:
|
251
|
+
response = requests.post(self.api_url, headers=self.headers, json=self.payload, timeout=timeout)
|
252
|
+
response_json = response.json()
|
253
|
+
if response.status_code == 200:
|
254
|
+
text_response = ""
|
255
|
+
for answer in response_json['response']:
|
256
|
+
# to-do --> pass the buttons in the answer?
|
257
|
+
if 'text' in answer:
|
258
|
+
text_response += answer['text']+"\n"
|
259
|
+
elif 'payload' in answer:
|
260
|
+
text_response += f"\n\nAVAILABLE BUTTONS:\n\n"
|
261
|
+
if 'cards' in answer['payload']:
|
262
|
+
for card in answer['payload']['cards']:
|
263
|
+
if 'buttons' in card:
|
264
|
+
text_response += self.__translate_buttons(card['buttons'])
|
265
|
+
elif 'buttons' in answer['payload']:
|
266
|
+
text_response += self.__translate_buttons(answer['payload']['buttons'])
|
267
|
+
|
268
|
+
return True, text_response
|
269
|
+
else:
|
270
|
+
# There is an error, but it is an internal error
|
271
|
+
print(f"Server error {response_json.get('error')}")
|
272
|
+
errors.append({500: f"Couldn't get response from the server"})
|
273
|
+
return False, response_json.get('error')
|
274
|
+
except requests.exceptions.JSONDecodeError as e:
|
275
|
+
logger = logging.getLogger('my_app_logger')
|
276
|
+
logger.error(f"Couldn't get response from the server: {e}")
|
277
|
+
return False, 'chatbot internal error'
|
278
|
+
except requests.Timeout:
|
279
|
+
logger = logging.getLogger('my_app_logger')
|
280
|
+
logger.error(f"No response was received from the server in less than {timeout}")
|
281
|
+
errors.append({504: f"No response was received from the server in less than {timeout}"})
|
282
|
+
return False, 'timeout'
|
283
|
+
|
284
|
+
|
285
|
+
def __translate_buttons(self, buttons_list) -> str:
|
286
|
+
text_response = ''
|
287
|
+
for button in buttons_list:
|
288
|
+
if 'text' in button:
|
289
|
+
text_response += f"- BUTTON TEXT: {button['text']}"
|
290
|
+
if 'value' in button:
|
291
|
+
text_response += f" LINK: {button['value']}\n"
|
292
|
+
else:
|
293
|
+
text_response += f" LINK: <empty>\n"
|
294
|
+
return text_response
|
295
|
+
|
296
|
+
|
297
|
+
class ChatbotTaskyto(Chatbot):
|
298
|
+
def __init__(self, connector):
|
299
|
+
Chatbot.__init__(self, connector)
|
300
|
+
self.id = None
|
301
|
+
self.connector_args = self.get_connector_args(connector)
|
302
|
+
self.api_url = self.connector_args["config"]["api_url"]
|
303
|
+
self.timeout = self.connector_args["config"]["timeout"]
|
304
|
+
|
305
|
+
def execute_with_input(self, user_msg):
|
306
|
+
if self.id is None:
|
307
|
+
try:
|
308
|
+
post_response = requests.post(self.api_url + '/conversation/new')
|
309
|
+
post_response_json = post_response.json()
|
310
|
+
self.id = post_response_json.get('id')
|
311
|
+
except requests.exceptions.ConnectionError:
|
312
|
+
logger.error(f"Couldn't connect with chatbot")
|
313
|
+
errors.append({500: f"Couldn't connect with chatbot"})
|
314
|
+
return False, 'cut connection'
|
315
|
+
except Exception:
|
316
|
+
logger.error(f"Server error: invalid payload")
|
317
|
+
errors.append({post_response.status_code: f"Server error"})
|
318
|
+
return False, 'chatbot server error'
|
319
|
+
|
320
|
+
if self.id is not None:
|
321
|
+
new_data = {
|
322
|
+
"id": self.id,
|
323
|
+
"message": user_msg
|
324
|
+
}
|
325
|
+
|
326
|
+
try:
|
327
|
+
try:
|
328
|
+
post_response = requests.post(self.api_url + '/conversation/user_message', json=new_data, timeout=self.timeout)
|
329
|
+
except requests.Timeout:
|
330
|
+
logger.error(f"No response was received from the server in less than {self.timeout}")
|
331
|
+
errors.append({504: f"No response was received from the server in less than {self.timeout}"})
|
332
|
+
return False, 'timeout'
|
333
|
+
except requests.exceptions.ConnectionError as e:
|
334
|
+
logger.error(f"Couldn't get response from the server: {e}")
|
335
|
+
errors.append({500: f"Couldn't get response from the server"})
|
336
|
+
return False, 'chatbot internal error'
|
337
|
+
|
338
|
+
post_response_json = post_response.json()
|
339
|
+
|
340
|
+
if post_response.status_code == 200:
|
341
|
+
assistant_message = post_response_json.get('message')
|
342
|
+
message = get_content(assistant_message) # get content process the message looking for images, pdf, or webpages
|
343
|
+
return True, message
|
344
|
+
|
345
|
+
else:
|
346
|
+
# There is an error, but it is an internal error
|
347
|
+
errors.append({500: "Chatbot internal error"})
|
348
|
+
return False, post_response_json.get('error')
|
349
|
+
except requests.exceptions.JSONDecodeError as e:
|
350
|
+
logger.error(f"Couldn't get response from the server: {e}")
|
351
|
+
errors.append({500: f"Couldn't get response from the server"})
|
352
|
+
return False, 'chatbot internal error'
|
353
|
+
|
354
|
+
return True, ''
|
355
|
+
|
356
|
+
def execute_starter_chatbot(self):
|
357
|
+
timeout = 20
|
358
|
+
try:
|
359
|
+
post_response = requests.post(self.api_url + '/conversation/new')
|
360
|
+
post_response_json = post_response.json()
|
361
|
+
self.id = post_response_json.get('id')
|
362
|
+
if post_response.status_code == 200:
|
363
|
+
assistant_message = post_response_json.get('message')
|
364
|
+
message = get_content(assistant_message)
|
365
|
+
if message is None:
|
366
|
+
return True, 'Hello'
|
367
|
+
else:
|
368
|
+
return True, message
|
369
|
+
else:
|
370
|
+
# There is an error, but it is an internal error
|
371
|
+
logger.error(f"Chatbot internal error")
|
372
|
+
errors.append({500: "Chatbot internal error"})
|
373
|
+
return False, post_response_json.get('error')
|
374
|
+
except requests.exceptions.ConnectionError:
|
375
|
+
logger.error(f"Couldn't connect with chatbot")
|
376
|
+
errors.append({500: f"Couldn't connect with chatbot"})
|
377
|
+
return False, 'cut connection'
|
378
|
+
except requests.Timeout:
|
379
|
+
logger.error(f"No response was received from the server in less than {timeout}")
|
380
|
+
errors.append({504: f"No response was received from the server in less than {timeout}"})
|
381
|
+
return False, 'timeout'
|
382
|
+
|
383
|
+
|
384
|
+
##############################################################################################################
|
385
|
+
# Serviceform
|
386
|
+
class ChatbotServiceform(Chatbot):
|
387
|
+
def __init__(self, connector):
|
388
|
+
Chatbot.__init__(self, connector)
|
389
|
+
|
390
|
+
self.connector_args = self.get_connector_args(connector)
|
391
|
+
|
392
|
+
self.api_url = self.connector_args["api_url"]
|
393
|
+
self.headers = self.connector_args["headers"]
|
394
|
+
self.payload = self.connector_args["payload"]
|
395
|
+
self.timeout = self.connector_args["timeout"]
|
396
|
+
|
397
|
+
# self.url = "https://dash.serviceform.com/api/ai"
|
398
|
+
# self.headers = {
|
399
|
+
# 'Content-Type': 'text/plain;charset=UTF-8'
|
400
|
+
# }
|
401
|
+
# self.payload = {"sid":"1729589460223tvzbcxe5zocgr5hs",
|
402
|
+
# "tid":"haGDRXUPY9tQOsOS44jY",
|
403
|
+
# "message":"Hello",
|
404
|
+
# "extraTraining":"",
|
405
|
+
# "assistant_id":"asst_PUNPPDAFOgHRLrlmHhDuQhCM"}
|
406
|
+
|
407
|
+
def execute_with_input(self, user_msg):
|
408
|
+
self.payload['message'] = user_msg
|
409
|
+
|
410
|
+
try:
|
411
|
+
response = requests.post(self.api_url, headers=self.headers, json=self.payload, timeout=self.timeout)
|
412
|
+
if response.status_code == 200:
|
413
|
+
data_bytes = response.content
|
414
|
+
data_str = data_bytes.decode('utf-8')
|
415
|
+
data_dict = json.loads(data_str)
|
416
|
+
return True, data_dict['response']
|
417
|
+
else:
|
418
|
+
# There is an error, but it is an internal error
|
419
|
+
print(f"Server error {response.status_code}")
|
420
|
+
errors.append({response.status_code: f"Couldn't get response from the server"})
|
421
|
+
return False, f"Something went wrong. Status Code: {response.status_code}"
|
422
|
+
except requests.exceptions.JSONDecodeError as e:
|
423
|
+
logger = logging.getLogger('my_app_logger')
|
424
|
+
logger.log(f"Couldn't get response from the server: {e}")
|
425
|
+
return False, 'chatbot internal error'
|
426
|
+
except requests.Timeout:
|
427
|
+
logger = logging.getLogger('my_app_logger')
|
428
|
+
logger.error(f"No response was received from the server in less than {self.timeout}")
|
429
|
+
errors.append({504: f"No response was received from the server in less than {self.timeout}"})
|
430
|
+
return False, 'timeout'
|
431
|
+
|
432
|
+
|
433
|
+
|
434
|
+
##############################################################################################################
|
435
|
+
# Kuki chatbot
|
436
|
+
# class KukiChatbot(Chatbot):
|
437
|
+
# def __init__(self, connector):
|
438
|
+
# Chatbot.__init__(self, connector)
|
439
|
+
#
|
440
|
+
# self.connector_args = self.get_connector_args(connector)
|
441
|
+
# self.api_url = self.connector_args["api_url"]
|
442
|
+
# self.headers = self.connector_args["headers"]
|
443
|
+
# self.payload = self.connector_args["payload"]
|
444
|
+
# self.timeout = self.connector_args["timeout"]
|
445
|
+
#
|
446
|
+
# # self.url = "https://kuli.kuki.ai/cptalk"
|
447
|
+
# # self.headers = {
|
448
|
+
# # 'Content-Type': 'application/x-www-form-urlencoded' # Standard for form data
|
449
|
+
# # }
|
450
|
+
# # self.payload = {
|
451
|
+
# # 'uid': 'da8bb9b3e54e9a4b',
|
452
|
+
# # 'input': 'Hello',
|
453
|
+
# # 'sessionid': '485255309'
|
454
|
+
# # }
|
455
|
+
#
|
456
|
+
# def execute_with_input(self, user_msg):
|
457
|
+
# self.payload['input'] = user_msg
|
458
|
+
#
|
459
|
+
# try:
|
460
|
+
# response = requests.post(self.api_url, headers=self.headers, data=self.payload, timeout=self.timeout)
|
461
|
+
# if response.status_code == 200:
|
462
|
+
# response_dict = json.loads(response.text)
|
463
|
+
# responses = response_dict['responses']
|
464
|
+
# all_responses = get_content('\n'.join(responses))
|
465
|
+
# return True, all_responses
|
466
|
+
# else:
|
467
|
+
# # There is an error, but it is an internal error
|
468
|
+
# print(f"Server error {response.status_code}")
|
469
|
+
# errors.append({response.status_code: f"Couldn't get response from the server"})
|
470
|
+
# return False, f"Something went wrong. Status Code: {response.status_code}"
|
471
|
+
# except requests.exceptions.JSONDecodeError as e:
|
472
|
+
# logger = logging.getLogger('my_app_logger')
|
473
|
+
# logger.log(f"Couldn't get response from the server: {e}")
|
474
|
+
# return False, 'chatbot internal error'
|
475
|
+
# except requests.Timeout:
|
476
|
+
# logger = logging.getLogger('my_app_logger')
|
477
|
+
# logger.error(f"No response was received from the server in less than {self.timeout}")
|
478
|
+
# errors.append({504: f"No response was received from the server in less than {self.timeout}"})
|
479
|
+
# return False, 'timeout'
|
480
|
+
#
|
481
|
+
#
|
482
|
+
# ##############################################################################################################
|
483
|
+
# # Julie chatbot
|
484
|
+
# class JulieChatbot(Chatbot):
|
485
|
+
# def __init__(self, connector):
|
486
|
+
# Chatbot.__init__(self, connector)
|
487
|
+
#
|
488
|
+
# self.connector_args = self.get_connector_args(connector)
|
489
|
+
# self.api_url = self.connector_args["api_url"]
|
490
|
+
# self.headers = self.connector_args["headers"]
|
491
|
+
# self.payload = self.connector_args["payload"]
|
492
|
+
# self.timeout = self.connector_args["timeout"]
|
493
|
+
#
|
494
|
+
# # self.url = 'https://askjulie2.nextit.com/AlmeAPI/api/Conversation/Converse'
|
495
|
+
# # self.headers = {
|
496
|
+
# # 'Content-Type': 'application/json',
|
497
|
+
# # }
|
498
|
+
# # self.payload = {"userId":"4b62a896-85f0-45dd-b94c-a6496f831107",
|
499
|
+
# # "sessionId":"724e371e-9917-4ab2-9da4-6809199366eb",
|
500
|
+
# # "question":"How are you?",
|
501
|
+
# # "origin":"Typed",
|
502
|
+
# # "displayText":"How are you?",
|
503
|
+
# # "parameters":{
|
504
|
+
# # "Context":{
|
505
|
+
# # "CurrentUrl":
|
506
|
+
# # {
|
507
|
+
# # "AbsolutePath":"https://www.amtrak.com/home.html",
|
508
|
+
# # "Protocol":"https:",
|
509
|
+
# # "Host":"www.amtrak.com",
|
510
|
+
# # "HostName":"www.amtrak.com",
|
511
|
+
# # "Port":"",
|
512
|
+
# # "Uri":"/home.html",
|
513
|
+
# # "Query":"",
|
514
|
+
# # "Fragment":"",
|
515
|
+
# # "Origin":"https://www.amtrak.com",
|
516
|
+
# # "Type":"embedded",
|
517
|
+
# # "PageName":"Amtrak Tickets, Schedules and Train Routes"
|
518
|
+
# # }
|
519
|
+
# # },
|
520
|
+
# # "UiVersion":"1.33.17"
|
521
|
+
# # },
|
522
|
+
# # "channel":"Web",
|
523
|
+
# # "language":"en-US",
|
524
|
+
# # "accessKey":"00000000-0000-0000-0000-000000000000"
|
525
|
+
# # }
|
526
|
+
#
|
527
|
+
# def execute_with_input(self, user_msg):
|
528
|
+
# self.payload['question'] = user_msg
|
529
|
+
# self.payload['displayText'] = user_msg
|
530
|
+
#
|
531
|
+
# try:
|
532
|
+
# response = requests.post(self.url, headers=self.headers, json=self.payload, timeout=self.timeout)
|
533
|
+
# if response.status_code == 200:
|
534
|
+
# response_dict = json.loads(response.text)
|
535
|
+
# chat_response = response_dict['text']
|
536
|
+
# if 'displayLinkCollection' in response_dict and response_dict['displayLinkCollection']:
|
537
|
+
# buttons = self.__translate_buttons(response_dict['displayLinkCollection'])
|
538
|
+
# chat_response += f"\n\n{buttons}"
|
539
|
+
# return True, chat_response
|
540
|
+
# else:
|
541
|
+
# # There is an error, but it is an internal error
|
542
|
+
# print(f"Server error {response.status_code}")
|
543
|
+
# errors.append({response.status_code: f"Couldn't get response from the server"})
|
544
|
+
# return False, f"Something went wrong. Status Code: {response.status_code}"
|
545
|
+
# except requests.exceptions.JSONDecodeError as e:
|
546
|
+
# logger = logging.getLogger('my_app_logger')
|
547
|
+
# logger.log(f"Couldn't get response from the server: {e}")
|
548
|
+
# return False, 'chatbot internal error'
|
549
|
+
# except requests.Timeout:
|
550
|
+
# logger = logging.getLogger('my_app_logger')
|
551
|
+
# logger.error(f"No response was received from the server in less than {self.timeout}")
|
552
|
+
# errors.append({504: f"No response was received from the server in less than {self.timeout}"})
|
553
|
+
# return False, 'timeout'
|
554
|
+
#
|
555
|
+
# def __translate_buttons(self, buttons_dict) -> str:
|
556
|
+
# button_description = 'AVAILABLE BUTTONS: '
|
557
|
+
# for section in buttons_dict['Sections']:
|
558
|
+
# for button in section["Links"]:
|
559
|
+
# button_text = ""
|
560
|
+
# if 'DisplayText' in button:
|
561
|
+
# button_text += f"- BUTTON TEXT: {button['DisplayText']}"
|
562
|
+
# if 'Metadata' in button and 'UnitUID' in button['Metadata']:
|
563
|
+
# button_text += f" LINK: {button['Metadata']['UnitUID']}\n"
|
564
|
+
# else:
|
565
|
+
# button_text += f" LINK: <empty>\n"
|
566
|
+
# button_description += f'\n {button_text}'
|
567
|
+
# return button_description
|
technologies/chatbots.py
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
import yaml
|
2
|
+
|
3
|
+
from typing import List, Dict
|
4
|
+
|
5
|
+
# -------------------------------------------------------------------------------------------------
|
6
|
+
# AUXILIARY CLASSES
|
7
|
+
# -------------------------------------------------------------------------------------------------
|
8
|
+
|
9
|
+
|
10
|
+
class Dumper(yaml.Dumper):
|
11
|
+
def increase_indent(self, flow=False, *args1, **kwargs1):
|
12
|
+
return super().increase_indent(flow=flow, indentless=False)
|
13
|
+
|
14
|
+
|
15
|
+
class ConversationConfiguration:
|
16
|
+
def __init__(self,
|
17
|
+
number_conversations: int = 1,
|
18
|
+
steps_in_conversation: int = 1,
|
19
|
+
interaction_style: List[str] = [],
|
20
|
+
change_language: List[str] = []
|
21
|
+
):
|
22
|
+
self.number = number_conversations
|
23
|
+
self.steps = steps_in_conversation
|
24
|
+
self.interaction_style = interaction_style
|
25
|
+
self.change_language = change_language
|
26
|
+
|
27
|
+
def to_dict(self):
|
28
|
+
interaction_to_dict: List[str | Dict] = [style for style in self.interaction_style]
|
29
|
+
if len(self.change_language):
|
30
|
+
interaction_to_dict.append({"change language": self.change_language})
|
31
|
+
return [
|
32
|
+
{"number": self.number},
|
33
|
+
{"goal_style": {"steps": self.steps}},
|
34
|
+
{"interaction_style": interaction_to_dict}
|
35
|
+
]
|
36
|
+
|
37
|
+
|
38
|
+
class RoleData:
|
39
|
+
def __init__(self,
|
40
|
+
temperature: float = 0.8,
|
41
|
+
isstarter: bool = True,
|
42
|
+
fallback: str = '',
|
43
|
+
role: str = '',
|
44
|
+
context: List[str] = None,
|
45
|
+
ask_about: List[str | Dict] = [],
|
46
|
+
conversations: ConversationConfiguration = ConversationConfiguration(),
|
47
|
+
language: str = 'English',
|
48
|
+
test_name: str = ''
|
49
|
+
):
|
50
|
+
self.temperature = temperature
|
51
|
+
self.isstarter = isstarter
|
52
|
+
self.fallback = fallback
|
53
|
+
self.role = role
|
54
|
+
self.context = context
|
55
|
+
self.ask_about = ask_about
|
56
|
+
self.conversations = conversations
|
57
|
+
self.language = language
|
58
|
+
self.test_name = test_name
|
59
|
+
|
60
|
+
def to_dict(self) -> dict:
|
61
|
+
ret = self.__dict__
|
62
|
+
ret['conversations'] = self.conversations.to_dict()
|
63
|
+
return ret
|
64
|
+
|
65
|
+
def to_yaml(self, file):
|
66
|
+
with open(file, 'w') as outfile:
|
67
|
+
yaml.dump(self.to_dict(), outfile, default_flow_style=False, sort_keys=False, Dumper=Dumper)
|
68
|
+
|
69
|
+
# -------------------------------------------------------------------------------------------------
|
70
|
+
# BASE CLASSES
|
71
|
+
# -------------------------------------------------------------------------------------------------
|
72
|
+
|
73
|
+
|
74
|
+
class ChatbotSpecification:
|
75
|
+
def build_user_profile(self, chatbot_folder) -> RoleData:
|
76
|
+
"""
|
77
|
+
:param chatbot_folder: folder containing the chatbot modules
|
78
|
+
:returns user profile built from the chatbot specification
|
79
|
+
"""
|
80
|
+
raise TypeError(f"Can't invoke abstract method build_user_profile in class {__class__.__name__}")
|