Reply contains diversion + fix for returning to story after diversion was broken
This commit is contained in:
parent
67d45fadbd
commit
331f5cf1d2
2 changed files with 144 additions and 6 deletions
|
@ -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
|
||||||
|
@ -500,6 +516,45 @@ class Diversion(object):
|
||||||
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):
|
||||||
"""
|
"""
|
||||||
Participant asks if message can be repeated.
|
Participant asks if message can be repeated.
|
||||||
|
@ -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()
|
||||||
|
|
|
@ -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 = {
|
||||||
|
@ -536,6 +541,68 @@ class Graph {
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
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(
|
||||||
'div', {'class': 'diversion'},
|
'div', {'class': 'diversion'},
|
||||||
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue