-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathactions.py
649 lines (567 loc) · 27.2 KB
/
actions.py
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
import os
import sys
import configparser
import random
from typing import Text, Dict, Any, List
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.events import SlotSet
import arrow
from num2words import num2words
from text2digits import text2digits
import roman
import sqlite3
ruler_gender_pronouns = {'queen':{'HeShe':'She'}, 'king':{'HeShe':'He'}}
def match_template(intent, fields):
templates = {
'ruler_list':{'fields': '$Name $Number'},
'ruler_before':{'fields': '$Name $Number'},
'ruler_after':{'fields': '$Name $Number'},
}
def nthwords2int(nthword):
"""Takes an "nth-word" (eg 3rd, 21st, 28th) strips off the ordinal ending
and returns the pure number."""
ordinal_ending_chars = 'stndrh' # from 'st', 'nd', 'rd', 'th'
try:
int_output = int(nthword.strip(ordinal_ending_chars))
except Exception as e:
raise Exception('Illegal nth-word: ' + nthword)
return int_output
def map_entity_to_number(ent):
"""Takes a complete entity and returns the corresponding number (as a
string)"""
# self.logger.debug(
# 'Entity: value: ' + ent['value'] + ' of type: ' + ent['entity'])
etype = ent['entity']
if etype == 'number':
# TODO: Add error and type checking
return ent['value']
if etype == 'number-roman':
# TODO: Add better error and type checking
try:
return str(roman.fromRoman(ent['value'].upper()))
except:
return None
if etype == 'nth':
# TODO: Add better error and type checking
try:
print('converting using nthwords2int')
return str(nthwords2int(ent['value'].lower()))
except:
return None
if etype in ('nth-words', 'number-words', 'year-words'):
# TODO: Add better error and type checking
try:
t2d = text2digits.Text2Digits()
return str(t2d.convert(ent['value'].lower()))
except:
return None
# so we couldn't match the etype to convert
return None
def map_feature_to_field(feature):
"""Takes a feature string and returns a list of the corresponding
database fieldname(s) (usually just one but can handle more)"""
#self.logger.debug('Feature to map: ' + feature)
f = feature.lower()
# NB: this structure assumes all features will be mapped by at least one of
# the conditions below; if you have acceptable features that should be
# passed through then some slight changes to the logic would be needed.
if f in ('events', 'happening', 'happenings'):
return ['NotableEventsDuringLife']
if f in ('describe', 'description', 'brief description', 'about'):
return ['Description']
if f in ('born', 'birth'):
return ['DtBirth']
if f in ('die', 'died', 'death'):
return ['DtDeath']
if f in ('king from','queen from', 'reign from', 'reign begin', 'reign began', 'reign start', 'started', 'become', 'rule from', 'rule start', 'rule began', 'on the throne', 'on throne'):
return ['ReignStartDt']
if f in ('king until','queen until', 'reign until', 'reign to', 'reign end', 'reign ended', 'end', 'become', 'rule until'):
return ['ReignEndDt']
if f in ('cause of death', 'killed', 'circumstances'):
return ['DeathCircumstances']
if f == 'house':
return ['House']
if f in ('portrait', 'picture', 'look', 'painting'):
return ['Portrait']
if f == 'title':
return ['Title']
if f in ('country', 'where'):
return ['Country']
if f in ('battle', 'battles', 'famous battles', 'wars', 'war', 'fight', 'fought'):
return ['FamousBattles']
if f in ('person', 'individual'):
return ['Name']
if f == 'number':
return ['Number']
if f in ('all', 'about'):
return ['Name', 'Number', 'DtBirth', 'DtDeath', 'ReignStartDt', 'ReignEndDt', 'FamousBattles', 'Description']
# so we didn't match anything
return []
def format_row(row, spoken=True):
for item in row:
if 'Dt' in str(item):
if (row[item] is not None) & (row[item] != '') & (row[item] != 'Present'):
try:
if spoken:
row[item] = str('the ' + num2words(int(arrow.get(str(row[item]), 'YYYY-MM-DD').format('D')), to='ordinal') + ' of ' + str(arrow.get(str(row[item]), 'YYYY-MM-DD').format('MMMM YYYY')))
else:
row[item] = str(arrow.get(str(row[item]), 'YYYY-MM-DD').format('D MMMM YYYY'))
except Exception as e:
print('Cannot convert contents of date field ' + str(item) + ' to a formatted date. ' + str(e))
if item in ('Number'):
if spoken:
row[item] = str('the ' + num2words(int(row[item]), to='ordinal'))
else:
row[item] = str(roman.toRoman(int(row[item])))
return row
def merge_output(row):
output = ''
for f in row:
try:
output = output + str(row[f]) + ', '
except UnicodeEncodeError:
output = output + str(row[f].encode('utf-8')) + ', '
# TODO: put something to take off the final comma
return output
def dict_factory(cursor, row):
"""Used for handling sqlite rows as dictionary (source: http://stackoverflow.com/questions/3300464/how-can-i-get-dict-from-sqlite-query)"""
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
#TODO think about where this sits best...
config = configparser.ConfigParser()
config_file = os.path.abspath(os.path.join('config', 'config_roybot.ini'))
try:
dataset = config.read([config_file])
if len(dataset) == 0:
raise IOError
except IOError as e:
print('Unable to open config file: ' + str(config_file))
#self.logger.warning('Unable to open config file: ' + str(config_file))
#self.before_quit()
except ConfigParser.Error as e:
print('Error with config file: ' + str(config_file))
# self.logger.warning('Error with config file: ' + str(config_file))
# self.before_quit()
sqlite_file = os.path.abspath(config.get('files', 'sqlite_file'))
print(sqlite_file)
db = sqlite3.connect(sqlite_file)
db.row_factory = dict_factory
cursor = db.cursor()
class ActionRulerList(Action):
def name(self) -> Text:
return "action_ruler_list"
async def run(self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
# """Handles the intent where a question seeks a list of rulers in a particular group or potentially the first or last of such a group."""
detail=False
### self.logger.info('Intent: ruler_list')
# Core query: SELECT * FROM `ruler` WHERE xyz... ORDER BY date(ReignStartDt)
# If all or first or last variant, must add:
# All: ASC
# First: ASC LIMIT 1
# Last: DESC LIMIT 1
# additional cases: if they list a year, then find ruler(s) in that year
# SELECT * FROM ruler WHERE CAST(STRFTIME('%Y', ReignStartDt) AS INT) <= 1400 AND CAST(STRFTIME('%Y', ReignEndDt) AS INT) >= 1400
sql = 'SELECT `Name`, `Number`, `RulerId`, `RulerType` FROM `ruler`'
fields = ['Name', 'Number']
country = None
house = None
position = None
year = None
century_start = None
century_end = None
ruler_type = None
where = []
params = {}
sql_suffix = ' ORDER BY date(ReignStartDt)'
ents = tracker.latest_message['entities']
print(ents)
for ent in ents:
if ent['entity'].lower() in (
'ruler_type', 'country', 'location', 'house', 'year', 'year-words', 'period', 'position'):
# self.logger.debug(
# 'Selection entity found: ' + ent['value'] +
# ' (' + ent['entity'] + ')')
if ent['entity'].lower() == 'ruler_type':
ruler_type = ent['value'].lower()
# TODO: consider breaking out this mapping into a generalised helper function
if ruler_type in ('king', 'kings', 'men', 'males'):
ruler_type = 'king'
if ruler_type in ('queen', 'queens', 'women', 'females'):
ruler_type = 'queen'
if ruler_type not in ('monarch', 'ruler', 'rulers', 'monarchs', 'leader', 'leaders'): # or any other non-restricting ruler_types
where.append('RulerType = :RulerType')
params['RulerType'] = ruler_type
if ent['entity'].lower() in ('country', 'location'):
# TODO: add ability to handle selection by one of a ruler's countries
# (eg select by England only if ruler rules England and Scotland)
country = ent['value']
where.append('Country LIKE :Country')
params['Country'] = '%' + country + '%'
if ent['entity'].lower() == 'house':
# TODO: make selection less brittle
house = ent['value']
where.append('House = :House')
params['House'] = house
if ent['entity'].lower() in ('year', 'year-words'):
if ent['entity'].lower() == 'year':
year = ent['value']
else:
year = map_entity_to_number(ent) # ie year-words
where.append("CAST(STRFTIME('%Y', ReignStartDt) AS INT) <= :Year AND CAST(STRFTIME('%Y', ReignEndDt) AS INT) >= :Year")
params['Year'] = year
if ent['entity'].lower() == 'period':
if ent['value'].lower() == 'century':
for n in ents:
if n['entity'].lower() in (
'number', 'number-roman', 'nth',
'nth-words', 'number-words'):
num = map_entity_to_number(n)
if num is not None:
century_end = int(num) * 100
century_start = century_end - 100
where.append("CAST(STRFTIME('%Y', ReignStartDt) AS INT) <= :CenturyEnd AND CAST(STRFTIME('%Y', ReignEndDt) AS INT) >= :CenturyStart")
params['CenturyEnd'] = century_end
params['CenturyStart'] = century_start
if ent['entity'].lower() == 'position':
position = ent['value'].lower()
# TODO: expand this to cope with second, third etc of
if position in ('first', 'earliest', 'start', 'beginning'):
sql_suffix = sql_suffix + ' ASC LIMIT 1'
if position in ('last', 'latest', 'final', 'end'):
sql_suffix = sql_suffix + ' DESC LIMIT 1'
# if ruler_type is not None:
# self.logger.debug('Ruler Type: ' + str(ruler_type))
# if country is not None:
# self.logger.debug('Country: ' + str(country))
# if house is not None:
# self.logger.debug('House: ' + str(house))
if position is not None:
print('Position: ' + str(position))
else:
sql_suffix = sql_suffix + ' ASC'
if where:
sql = '{} WHERE {}'.format(sql, ' AND '.join(where))
sql = sql + sql_suffix
print('SQL: ' + sql)
print('Params: ' + str(params))
try:
cursor.execute(sql, params)
except sqlite3.Error as e:
dispatcher.utter_message(text = 'I experienced a problem answering that question. Could we try another question instead?')
return
output = ''
results = cursor.fetchall()
last_ruler_count = len(results)
print(f'{last_ruler_count = }')
if last_ruler_count == 1:
last_ruler_id = str(results[0]['RulerId'])
print(f'Set {last_ruler_id =}')
else:
last_ruler_id = None
if last_ruler_count == 0:
if self.name() == "action_ruler_pronoun_feature":
dispatcher.utter_message(text ='I am not aware of a recently referenced ruler. Try asking about a specific person (eg Elizabeth the First).')
else:
dispatcher.utter_message(text ='Based on my understanding of your question, I am not able to match any rulers. You may have a typo or a non-existent combination (eg Richard the Seventh).')
if (position is not None) and (last_ruler_count > 1):
dispatcher.utter_message(text ='It looks like you were after a specific ruler, but I am matching several (so perhaps something went wrong, either with how the question was asked or how I understood it).')
dispatcher.utter_message(text ='Here they are anyway:')
print(f'{results=} {len(results)=}')
for row in results:
row = format_row(row)
print(row["Name"])
#output = output + merge_output(row) + '\n'
output = output + f'{row["Name"]} {row["Number"]}.\n'
dispatcher.utter_message(text = f'{output}')
return [SlotSet("last_ruler_id", last_ruler_id)]
class ActionRulerCombinedBeforeAfter(Action):
def name(self) -> Text:
return "action_ruler_combined_before_after"
async def run(self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
print(f'Intent: {self.name()}')
before = self.name() == "action_ruler_before"
## Before
# SELECT *
# FROM ruler
# WHERE RulerId < (SELECT RulerId FROM ruler WHERE Name = 'Henry' AND `Number` = '8')
# ORDER BY RulerId DESC
# LIMIT 1
## After
# SELECT *
# FROM ruler
# WHERE RulerId > (SELECT RulerId FROM ruler WHERE Name = 'Henry' AND `Number` = '8')
# ORDER BY RulerId
# LIMIT 1
sql = "SELECT `Name`, `Number`, `RulerId`, `RulerType` FROM ruler WHERE RulerId "
sql_middle = " (SELECT RulerId FROM ruler"
if before:
sql = sql + '<' + sql_middle
sql_suffix = "ORDER BY RulerId DESC LIMIT 1"
else:
# after
sql = sql + '>' + sql_middle
sql_suffix = "ORDER BY RulerId LIMIT 1"
fields = ['Name', 'Number']
num = None
loc = None
ruler_type = None
where = []
sub_where = []
params = {}
ents = tracker.latest_message['entities']
for ent in ents:
if ent['entity'].lower() in (
'name', 'location', 'number', 'number-words',
'number-roman', 'nth-words', 'nth', 'title','ruler_type'):
# self.logger.debug(
# 'Selection entity found: ' + ent['value'] +
# ' (' + ent['entity'] + ')')
if ent['entity'].lower() == 'ruler_type':
ruler_type = ent['value'].lower()
# TODO: consider breaking out this mapping into a generalised helper function
if ruler_type in ('king', 'kings', 'men', 'males'):
ruler_type = 'king'
if ruler_type in ('queen', 'queens', 'women', 'females'):
ruler_type = 'queen'
if ruler_type not in ('monarch', 'ruler', 'rulers', 'monarchs', 'leader', 'leaders'): # or any other non-restricting ruler_types
where.append('RulerType = :RulerType')
params['RulerType'] = ruler_type
if ent['entity'].lower() == 'name':
name = ent['value']
sub_where.append('Name = :Name')
params['Name'] = name
if ent['entity'].lower() == 'title':
title = ent['value']
sub_where.append('Title = :Title')
params['Title'] = title
if ent['entity'].lower() == 'location':
loc = ent['value']
sub_where.append('Country LIKE :Location')
params['Location'] = '%' + loc + '%'
if ent['entity'].lower() in (
'number', 'number-roman', 'nth',
'nth-words', 'number-words'):
num = map_entity_to_number(ent)
if num is not None:
sub_where.append('Number = :Number')
params['Number'] = num
# if loc is not None:
# self.logger.debug('Loc: ' + str(loc))
# if num is not None:
# self.logger.debug('Num: ' + str(num))
if where:
sql_suffix = ") AND {} ".format(' AND '.join(where)) + sql_suffix
else:
sql_suffix = ") " + sql_suffix
if sub_where:
sql = '{} WHERE {}'.format(sql, ' AND '.join(sub_where))
sql = sql + sql_suffix
print('SQL: ' + sql)
print('Params: ' + str(params))
try:
cursor.execute(sql, params)
except sqlite3.Error as e:
dispatcher.utter_message(text = 'I experienced a problem answering that question. Could we try another question instead?')
return
output = ''
results = cursor.fetchall()
last_ruler_count = len(results)
print(f'{last_ruler_count = }')
#self.user['last_ruler_count'] = len(results)
if last_ruler_count == 1:
last_ruler_id = str(results[0]['RulerId'])
print(f'Set {last_ruler_id =}')
else:
last_ruler_id = None
if last_ruler_count == 0:
if self.name() == "action_ruler_pronoun_feature":
dispatcher.utter_message(text ='I am not aware of a recently referenced ruler. Try asking about a specific person (eg Elizabeth the First).')
else:
dispatcher.utter_message(text ='Based on my understanding of your question, I am not able to match any rulers. You may have a typo or a non-existent combination (eg Richard the Seventh).')
else:
dispatcher.utter_message(text = 'Based on my understanding of your question, I\'m having trouble narrowing down the selection to a single ruler. You may need to be a little more specific.')
return [SlotSet("last_ruler_id", last_ruler_id)]
for row in results:
row = format_row(row)
print(row)
#output = merge_output(row)
output = output + f'{row["Name"]} {row["Number"]}.\n'
#dispatcher.utter_message(text = f'The ruler before after was run based on {self.name()}.')
dispatcher.utter_message(text = f'{output}')
return [SlotSet("last_ruler_id", last_ruler_id)]
class ActionRulerBefore(ActionRulerCombinedBeforeAfter):
"""Class inherits from ActionRulerCombinedBeforeAfter because the vast majority of the class functionality required is the same
whether it's a before and an after scenario.
Simply inherit and then add a few checks within the combined class where they need to act differently."""
def name(self) -> Text:
return "action_ruler_before"
class ActionRulerAfter(ActionRulerCombinedBeforeAfter):
"""Class inherits from ActionRulerCombinedBeforeAfter because the vast majority of the class functionality required is the same
whether it's a before and an after scenario.
Simply inherit and then add a few checks within the combined class where they need to act differently."""
def name(self) -> Text:
return "action_ruler_after"
class ActionExample(Action):
def name(self) -> Text:
return "action_example"
async def run(self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
example_list = random.choice([
'In the House of Anjou who was the last ruler?',
'Tell me all about Henry the Eighth',
'Who was king after Richard the Lionheart?',
'What date was Elizabeth the First born?',
'What were the circumstances of Edward the Second\'s death?',
'What can I say?'
])
suggestion_intro = random.choice([
'Here\'s an example to try:\n\t',
'How about this?\n\t',
'Give this a go!\n\t'])
dispatcher.utter_message(text = f'{suggestion_intro} {example_list}')
return []
class ActionRulerFeature(Action):
def name(self) -> Text:
return "action_ruler_feature"
async def run(self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
#TODO: fix this based on the royboy.py code
detail = False
#name = tracker.get_slot('name')
#name = next(tracker.get_latest_entity_values("name"), None)
#features = list(tracker.get_latest_entity_values("feature"))
#print(features)
ents = tracker.latest_message['entities']
print(ents)
sql = 'SELECT DISTINCT {fields} FROM `ruler`'
num = None
loc = None
fields = []
where = []
params = {}
for ent in ents:
if ent['entity'].lower() in (
'name', 'location', 'number', 'number-words',
'number-roman', 'nth-words', 'nth', 'title'):
# self.logger.debug(
# 'Selection entity found: ' + ent['value'] +
# ' (' + ent['entity'] + ')')
if ent['entity'].lower() == 'name':
name = ent['value']
where.append('Name = :Name')
params['Name'] = name
if ent['entity'].lower() == 'title':
title = ent['value']
where.append('Title = :Title')
params['Title'] = title
if ent['entity'].lower() == 'location':
loc = ent['value']
where.append('Country LIKE :Location')
params['Location'] = '%' + loc + '%'
if ent['entity'].lower() in (
'number', 'number-roman', 'nth',
'nth-words', 'number-words'):
num = map_entity_to_number(ent)
if num is not None:
where.append('Number = :Number')
params['Number'] = num
else:
if not detail:
# self.logger.info(
# 'A field related entity was found: ' +
# ent['value'] + ' (' + ent['entity'] + ')')
f = map_feature_to_field(ent['value'])
if (f is not None) & (f not in fields):
fields = fields + f
#print(f'fields: {str(fields)}')
print(f'{self.name() =}')
if self.name() == "action_ruler_pronoun_feature":
where = ["RulerId = :RulerId"]
params['RulerId'] = tracker.get_slot('last_ruler_id')
if 'RulerId' not in fields:
fields.append('RulerId')
if 'RulerType' not in fields:
fields.append('RulerType')
if 'Portrait' in fields:
fields.append('Name')
fields.append('Number')
# self.logger.debug('Fields: ' + str(fields))
# if overload_item is not None:
# self.logger.debug('Overload item: ' + str(overload_item))
# if loc is not None:
# self.logger.debug('Loc: ' + str(loc))
# if num is not None:
# self.logger.debug('Num: ' + str(num))
if fields:
sql = sql.format(fields=', '.join(fields))
else:
sql = sql.format(fields='*')
if where:
sql = '{} WHERE {}'.format(sql, ' AND '.join(where))
print('SQL: ' + sql)
print('Params: ' + str(params))
try:
cursor.execute(sql, params)
except sqlite3.Error as e:
dispatcher.utter_message(text = 'I experienced a problem answering that question. Could we try another question instead?')
return []
output = ''
results = cursor.fetchall()
last_ruler_count = len(results)
print(f'{last_ruler_count = }')
# self.logger.debug('Last ruler count: ' + str(self.user['last_ruler_count']))
if last_ruler_count == 1:
last_ruler_id = str(results[0]['RulerId'])
print(f'Set {last_ruler_id =}')
else:
last_ruler_id = None
if last_ruler_count == 0:
if self.name() == "action_ruler_pronoun_feature":
dispatcher.utter_message(text ='I am not aware of a recently referenced ruler. Try asking about a specific person (eg Elizabeth the First).')
else:
dispatcher.utter_message(text ='Based on my understanding of your question, I am not able to match any rulers. You may have a typo or a non-existent combination (eg Richard the Seventh).')
else:
dispatcher.utter_message(text ='Based on my understanding of your question, I cannot narrow down the selection to a single ruler. You may need to be a little more specific.')
return [SlotSet("last_ruler_id", last_ruler_id)]
reply = ''
print(f'{results=}')
for row in results:
row = format_row(row)
#dispatcher.utter_message(text = f"{', '.join(fields)}:\n{params}\n{reply}")
#dispatcher.utter_message(text = f"SQL generated is:\n{sql}\nParameters are:\n{params}\n{reply}")
#dispatcher.utter_message(text = f"{reply}\nSQL generated is:\n{sql}")
#kw = {'Portrait':'Victoria'}
print(f'{fields[0] =}')
pronouns = ruler_gender_pronouns[results[0]['RulerType']]
results[0].update(pronouns)
if fields[0] == 'Portrait':
print(f'Portrait: {results[0]["Portrait"]}')
dispatcher.utter_message(text = f'A picture of {results[0]["Name"]} {results[0]["Number"]}.', image = results[0]['Portrait'])
#dispatcher.utter_message(response = 'utter_ruler_feature_Portrait', **results[0], image = results[0]['Portrait'])
return [SlotSet("last_ruler_id", last_ruler_id)]
if len(fields) > 5:
utterance_built = 'utter_ruler_feature_all'
else:
utterance_built = 'utter_ruler_feature_' + fields[0]
print(f'{utterance_built =}')
dispatcher.utter_message(response = utterance_built, **results[0])
return [SlotSet("last_ruler_id", last_ruler_id)]
class ActionRulerPronounFeature(ActionRulerFeature):
"""Class inherits from ActionRulerCombinedBeforeAfter because the vast majority of the class functionality required is the same
whether it's a before and an after scenario.
Simply inherit and then add a few checks within the combined class where they need to act differently."""
def name(self) -> Text:
return "action_ruler_pronoun_feature"