Reply contains diversion + fix for returning to story after diversion was broken

This commit is contained in:
Ruben van de Ven 2019-04-24 13:38:41 +02:00
parent 67d45fadbd
commit 331f5cf1d2
2 changed files with 144 additions and 6 deletions

View File

@ -432,10 +432,22 @@ class Diversion(object):
self.id = id
self.params = params
self.finaliseMethod = None
self.hasHit = False
if type == 'no_response':
self.method = self._divergeIfNoResponse
self.finaliseMethod = self._returnAfterNoResponse
self.counter = 0
if type == 'reply_contains':
self.method = self._divergeIfReplyContains
self.finaliseMethod = self._returnAfterReplyContains
if len(self.params['regex']) > 0:
self.regex = re.compile(self.params['regex'])
else:
self.regex = None
# if type == 'timeout':
# self.method = self._divergeIfNoResponse
# self.finaliseMethod = self._returnAfterNoResponse
if type == 'repeat':
self.method = self._divergeIfRepeatRequest
self.regex = re.compile(self.params['regex'])
@ -460,13 +472,17 @@ class Diversion(object):
Validate if condition is met for the current story state
Returns True when diverging
"""
return await self.method(story, msgFrom, msgTo)
r = await self.method(story, msgFrom, msgTo)
if r:
self.hasHit = True
return r
async def finalise(self, story):
""""
Only used if the Diversion sets the story.currentDiversion
"""
if not self.finaliseMethod:
story.logger.info(f"No finalisation for diversion {self.id}")
return False
await self.finaliseMethod(story)
return True
@ -499,6 +515,45 @@ class Diversion(object):
story.stats['consecutiveSilentTimeouts'] = 0 # reset counter after diverging
if self.params['returnAfterStrand']:
await story.setCurrentMessage(self.returnMessage)
async def _divergeIfReplyContains(self, story, msgFrom, msgTo):
"""
Participant doesn't speak for x consecutive replies (has had timeout)
"""
':type story: Story'
if story.currentDiversion:
# don't do nested diversions
# if we remove this, don't forget to double check 'returnMessage'
return False
if self.hasHit:
# don't match twice
return
if story.currentReply is None or not self.regex:
return
r = self.regex.search(story.currentReply.getText())
if r is None:
return
logger.info(f"Diverge: reply contains {self.id}")
story.stats['diversions']['reply_contains'] += 1
msg = story.get(self.params['msgId'])
if msg is None:
story.logger.critical(f"Not a valid message id for diversion: {self.params['msgId']}")
return
self.returnMessage = msgTo
await story.setCurrentMessage(msg)
story.currentDiversion = self
return True
async def _returnAfterReplyContains(self, story):
story.logger.info(f"Finalise diversion: {self.id}")
if self.params['returnAfterStrand']:
await story.setCurrentMessage(self.returnMessage)
async def _divergeIfRepeatRequest(self, story, msgFrom, msgTo):
"""
@ -708,6 +763,8 @@ class Story(object):
'diversions': {
'no_response': 0,
'repeat': 0,
'reply_contains': 0,
'timeout': 0
}
}
@ -781,13 +838,14 @@ class Story(object):
# self.hugvey.google.resume()
if self.currentMessage.id not in self.directionsPerMsg:
print(self.currentDiversion)
if self.currentDiversion is not None:
self.logger.info("end of diversion")
await self.currentDiversion.finalise(self)
self.currentDiversion = None
else:
self.logger.info("THE END!")
self.stop()
self.finish()
return
if e['event'] == 'speech':
@ -882,8 +940,7 @@ class Story(object):
for i in range(len(self.events)):
await self._processPendingEvents()
if self.currentMessage.id not in self.directionsPerMsg:
self.finish()
# The finish is not here anymore, but only on the playbackFinish event.
directions = self.getCurrentDirections()
await self._processDirections(directions)
@ -998,6 +1055,7 @@ class Story(object):
def finish(self):
self.logger.info(f"Finished story for {self.hugvey.id}")
self.hugvey.eventLogger.info("story: finished")
self.stop()
self.hugvey.pause()
self.finish_time = time.time()
self.timer.pause()

View File

@ -440,6 +440,11 @@ class Graph {
div['params']['returnAfterStrand'] = true;
div['params']['msgId'] = "";
}
else if(type == 'reply_contains') {
div['params']['regex'] = "";
div['params']['returnAfterStrand'] = true;
div['params']['msgId'] = "";
}
else if(type == 'repeat') {
div['params']['regex'] = "can you repeat that\\?";
} else {
@ -464,7 +469,7 @@ class Graph {
let msgEl = document.getElementById( 'msg' );
msgEl.innerHTML = "";
let divsNoResponse =[], divsRepeat = [];
let divsNoResponse =[], divsRepeat = [], divsReplyContains = [], divsTimeouts = [];
for(let div of this.diversions) {
if(div['type'] == 'no_response') {
let returnAttrs = {
@ -535,6 +540,68 @@ class Graph {
}}, ...msgOptions)
)
));
}
if(div['type'] == 'reply_contains') {
let returnAttrs = {
'type': 'checkbox',
'on': {
'change': (e) => div['params']['returnAfterStrand'] = e.target.checked
}
}
if(div['params']['returnAfterStrand']) {
returnAttrs['checked'] = 'checked';
}
let msgOptions = [crel('option',"")];
let starts = this.messages.filter( m => m.hasOwnProperty('start') && m['start'] == true);
for(let startMsg of starts) {
let optionParams = {};
if(div['params']['msgId'] == startMsg['@id']) {
optionParams['selected'] = 'selected';
}
msgOptions.push(crel('option', optionParams , startMsg['@id']));
}
divsReplyContains.push(crel(
'div', {
'class': 'diversion',
'on': {
'mouseover': function(e) {
if(div['params']['msgId'])
document.getElementById(div['params']['msgId']).classList.add('selectedMsg');
},
'mouseout': function(e) {
if(div['params']['msgId'])
document.getElementById(div['params']['msgId']).classList.remove('selectedMsg');
}
}
},
crel('h3', div['@id']),
crel(
'div', {
'class':'btn btn--delete',
'on': {
'click': (e) => this.deleteDiversion(div)
}
}, 'Delete diversion'),
crel('label', 'Regex',
crel('input', {
'type': 'text',
'value': div['params']['regex'],
'placeholder': 'regex',
'on': {
'change': (e) => div['params']['regex'] = e.target.value
}
})
),
crel('label', 'Return to point of departure afterwards',
crel('input', returnAttrs)
),
crel('label', 'Go to (start message)',
crel('select', {'on': {
'change': (e) => div['params']['msgId'] = e.target.value
}}, ...msgOptions)
)
));
}
if(div['type'] == 'repeat'){
divsRepeat.push(crel(
@ -560,7 +627,7 @@ class Graph {
}
}
console.log(divsNoResponse, divsRepeat);
console.log(divsReplyContains, divsNoResponse, divsRepeat);
let divEl = crel(
'div',
@ -581,6 +648,19 @@ class Graph {
'New case for no_response'
)
),
crel('div',
crel('h2', 'Reply Contains'),
...divsReplyContains,
crel('div',
{
'class': 'btn',
'on': {
'click': (e) => this.createDiversion('reply_contains')
}
},
'New case for reply contains'
)
),
crel('div',
crel('h2', 'Request repeat'),
...divsRepeat,