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.id = id
self.params = params self.params = params
self.finaliseMethod = None self.finaliseMethod = None
self.hasHit = False
if type == 'no_response': if type == 'no_response':
self.method = self._divergeIfNoResponse self.method = self._divergeIfNoResponse
self.finaliseMethod = self._returnAfterNoResponse self.finaliseMethod = self._returnAfterNoResponse
self.counter = 0 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': if type == 'repeat':
self.method = self._divergeIfRepeatRequest self.method = self._divergeIfRepeatRequest
self.regex = re.compile(self.params['regex']) self.regex = re.compile(self.params['regex'])
@ -460,13 +472,17 @@ class Diversion(object):
Validate if condition is met for the current story state Validate if condition is met for the current story state
Returns True when diverging 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): async def finalise(self, story):
"""" """"
Only used if the Diversion sets the story.currentDiversion Only used if the Diversion sets the story.currentDiversion
""" """
if not self.finaliseMethod: if not self.finaliseMethod:
story.logger.info(f"No finalisation for diversion {self.id}")
return False return False
await self.finaliseMethod(story) await self.finaliseMethod(story)
return True return True
@ -499,6 +515,45 @@ class Diversion(object):
story.stats['consecutiveSilentTimeouts'] = 0 # reset counter after diverging story.stats['consecutiveSilentTimeouts'] = 0 # reset counter after diverging
if self.params['returnAfterStrand']: if self.params['returnAfterStrand']:
await story.setCurrentMessage(self.returnMessage) 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): async def _divergeIfRepeatRequest(self, story, msgFrom, msgTo):
""" """
@ -708,6 +763,8 @@ class Story(object):
'diversions': { 'diversions': {
'no_response': 0, 'no_response': 0,
'repeat': 0, 'repeat': 0,
'reply_contains': 0,
'timeout': 0
} }
} }
@ -781,13 +838,14 @@ class Story(object):
# self.hugvey.google.resume() # self.hugvey.google.resume()
if self.currentMessage.id not in self.directionsPerMsg: if self.currentMessage.id not in self.directionsPerMsg:
print(self.currentDiversion)
if self.currentDiversion is not None: if self.currentDiversion is not None:
self.logger.info("end of diversion") self.logger.info("end of diversion")
await self.currentDiversion.finalise(self) await self.currentDiversion.finalise(self)
self.currentDiversion = None self.currentDiversion = None
else: else:
self.logger.info("THE END!") self.logger.info("THE END!")
self.stop() self.finish()
return return
if e['event'] == 'speech': if e['event'] == 'speech':
@ -882,8 +940,7 @@ class Story(object):
for i in range(len(self.events)): for i in range(len(self.events)):
await self._processPendingEvents() await self._processPendingEvents()
if self.currentMessage.id not in self.directionsPerMsg: # The finish is not here anymore, but only on the playbackFinish event.
self.finish()
directions = self.getCurrentDirections() directions = self.getCurrentDirections()
await self._processDirections(directions) await self._processDirections(directions)
@ -998,6 +1055,7 @@ class Story(object):
def finish(self): def finish(self):
self.logger.info(f"Finished story for {self.hugvey.id}") self.logger.info(f"Finished story for {self.hugvey.id}")
self.hugvey.eventLogger.info("story: finished") self.hugvey.eventLogger.info("story: finished")
self.stop()
self.hugvey.pause() self.hugvey.pause()
self.finish_time = time.time() self.finish_time = time.time()
self.timer.pause() self.timer.pause()

View File

@ -440,6 +440,11 @@ class Graph {
div['params']['returnAfterStrand'] = true; div['params']['returnAfterStrand'] = true;
div['params']['msgId'] = ""; div['params']['msgId'] = "";
} }
else if(type == 'reply_contains') {
div['params']['regex'] = "";
div['params']['returnAfterStrand'] = true;
div['params']['msgId'] = "";
}
else if(type == 'repeat') { else if(type == 'repeat') {
div['params']['regex'] = "can you repeat that\\?"; div['params']['regex'] = "can you repeat that\\?";
} else { } else {
@ -464,7 +469,7 @@ class Graph {
let msgEl = document.getElementById( 'msg' ); let msgEl = document.getElementById( 'msg' );
msgEl.innerHTML = ""; msgEl.innerHTML = "";
let divsNoResponse =[], divsRepeat = []; let divsNoResponse =[], divsRepeat = [], divsReplyContains = [], divsTimeouts = [];
for(let div of this.diversions) { for(let div of this.diversions) {
if(div['type'] == 'no_response') { if(div['type'] == 'no_response') {
let returnAttrs = { let returnAttrs = {
@ -535,6 +540,68 @@ class Graph {
}}, ...msgOptions) }}, ...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'){ if(div['type'] == 'repeat'){
divsRepeat.push(crel( divsRepeat.push(crel(
@ -560,7 +627,7 @@ class Graph {
} }
} }
console.log(divsNoResponse, divsRepeat); console.log(divsReplyContains, divsNoResponse, divsRepeat);
let divEl = crel( let divEl = crel(
'div', 'div',
@ -581,6 +648,19 @@ class Graph {
'New case for no_response' '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('div',
crel('h2', 'Request repeat'), crel('h2', 'Request repeat'),
...divsRepeat, ...divsRepeat,