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.
@@ -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
@@ -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__}")