Faster interface and timing factor

This commit is contained in:
Ruben van de Ven 2019-11-11 18:25:04 +01:00
parent 925e7187fd
commit 9df1d77b4f
4 changed files with 101 additions and 52 deletions

View file

@ -372,7 +372,7 @@ class Condition(object):
# else: # else:
# story.logger.debug('Only if no reply has no text yet!') # story.logger.debug('Only if no reply has no text yet!')
hasMetTimeout = now - story.lastMsgFinishTime >= float(self.vars['seconds']) hasMetTimeout = now - story.lastMsgFinishTime >= story.applyTimeFactor(self.vars['seconds'])
if not hasMetTimeout: if not hasMetTimeout:
return False return False
@ -575,7 +575,7 @@ class Condition(object):
if replyDuration > float(delay['minReplyDuration']): if replyDuration > float(delay['minReplyDuration']):
timeSinceReply = r.getTimeSinceLastUtterance() timeSinceReply = r.getTimeSinceLastUtterance()
story.logger.log(LOG_BS, f"check delay duration is now {replyDuration}, already waiting for {timeSinceReply}, have to wait {delay['waitTime']}") story.logger.log(LOG_BS, f"check delay duration is now {replyDuration}, already waiting for {timeSinceReply}, have to wait {delay['waitTime']}")
if timeSinceReply > float(delay['waitTime']): if timeSinceReply > story.applyTimeFactor(delay['waitTime']):
# if variables are captured, only set them the moment the condition matches # if variables are captured, only set them the moment the condition matches
if capturedVariables is not None: if capturedVariables is not None:
for captureGroup in capturedVariables: for captureGroup in capturedVariables:
@ -585,7 +585,7 @@ class Condition(object):
capturedVariables, capturedVariables,
timeSinceReply timeSinceReply
) )
self.usedContainsDuration = float(delay['waitTime']) self.usedContainsDuration = story.applyTimeFactor(delay['waitTime'])
return True return True
break # don't check other delays break # don't check other delays
# wait for delay to match # wait for delay to match
@ -897,7 +897,7 @@ class Diversion(object):
# ignore the direction argument, and only check if the current message has a valid default # ignore the direction argument, and only check if the current message has a valid default
return return
waitTime = 1.8 if 'waitTime' not in self.params else float(self.params['waitTime']) waitTime = story.applyTimeFactor(1.8 if 'waitTime' not in self.params else float(self.params['waitTime']))
timeSince = story.currentReply.getTimeSinceLastUtterance() timeSince = story.currentReply.getTimeSinceLastUtterance()
if timeSince < waitTime: if timeSince < waitTime:
story.logger.log(LOG_BS, f"Waiting for replyContains: {timeSince} (needs {waitTime})") story.logger.log(LOG_BS, f"Waiting for replyContains: {timeSince} (needs {waitTime})")
@ -984,7 +984,7 @@ class Diversion(object):
# TODO: how to handle this now we sometimes use different timings. # TODO: how to handle this now we sometimes use different timings.
# Perhaps set isFinished when matching condition. # Perhaps set isFinished when matching condition.
if story.currentReply is None or story.currentReply.getTimeSinceLastUtterance() < 1.8: if story.currentReply is None or story.currentReply.getTimeSinceLastUtterance() < story.applyTimeFactor(1.8):
return return
if story.currentMessage.didRepeat: if story.currentMessage.didRepeat:
@ -1025,12 +1025,12 @@ class Diversion(object):
return return
now = story.timer.getElapsed() now = story.timer.getElapsed()
if now - story.lastMsgFinishTime < float(self.params['minTimeAfterMessage']): if now - story.lastMsgFinishTime < story.applyTimeFactor(self.params['minTimeAfterMessage']):
# not less than x sec after it # not less than x sec after it
return return
interval = float(self.params['interval']) interval = story.applyTimeFactor(self.params['interval'])
if not self.params['fromLastMessage']: if not self.params['fromLastMessage']:
# (1) last spoken at all # (1) last spoken at all
@ -1115,6 +1115,7 @@ class Configuration(object):
id = 'configuration' id = 'configuration'
volume = 1 # Volume multiplier for 'play' command volume = 1 # Volume multiplier for 'play' command
nothing_text = "nothing" # When variable is not set, but used in sentence, replace it with this word. nothing_text = "nothing" # When variable is not set, but used in sentence, replace it with this word.
time_factor = 1
light0_intensity = 0 light0_intensity = 0
light0_fade = 30. # fade duration in seconds light0_fade = 30. # fade duration in seconds
light1_intensity = 150 light1_intensity = 150
@ -1954,6 +1955,15 @@ class Story(object):
return self.calculateFinishesForMsg(msg.id, checked=[]) return self.calculateFinishesForMsg(msg.id, checked=[])
def applyTimeFactor(self, time) -> float:
"""
Apply the particularities of the configuration.time_factor
"""
time = float(time)
if time < 1:
return time
return time * self.configuration.time_factor
def getDefaultDirectionForMsg(self, msg): def getDefaultDirectionForMsg(self, msg):
""" """
There is only a default direction (for reply contains diversion) if it has There is only a default direction (for reply contains diversion) if it has

View file

@ -43,6 +43,16 @@ body.dark {
.btn:hover, input[type="submit"]:hover { .btn:hover, input[type="submit"]:hover {
background: #666; } background: #666; }
.btn.loading:after {
display: inline-block;
content: '';
width: 15px;
height: 15px;
background-color: white;
border-radius: 100%;
-webkit-animation: sk-scaleout 1.0s infinite ease-in-out;
animation: sk-scaleout 1.0s infinite ease-in-out; }
input[type="number"] { input[type="number"] {
width: 80px; width: 80px;
text-align: right; } text-align: right; }
@ -91,15 +101,6 @@ img.icon {
color: #ccc; color: #ccc;
list-style: none; list-style: none;
padding: 0; } padding: 0; }
#status > div#overview #languages .loading:after {
display: inline-block;
content: '';
width: 15px;
height: 15px;
background-color: white;
border-radius: 100%;
-webkit-animation: sk-scaleout 1.0s infinite ease-in-out;
animation: sk-scaleout 1.0s infinite ease-in-out; }
#status .counts dd, #status .counts dt { #status .counts dd, #status .counts dt {
display: inline-block; display: inline-block;
width: 30px; width: 30px;

View file

@ -324,7 +324,16 @@ class Graph {
this.linkG = this.container.append( "g" ) this.linkG = this.container.append( "g" )
.attr( "id", "links" ); .attr( "id", "links" );
document.getElementById( 'btn-save' ).addEventListener( 'click', function( e ) { graph.saveJson(); } ); document.getElementById( 'btn-save' ).addEventListener( 'click', function( e ) {
let el = e.target;
el.classList.add('loading');
// give the ui a fraction to actually apply the 'loading' class
setTimeout(function(){
graph.saveJson();
el.classList.remove('loading');
}, 100);
} );
document.getElementById( 'btn-addMsg' ).addEventListener( 'click', function( e ) { graph.createMsg(); } ); document.getElementById( 'btn-addMsg' ).addEventListener( 'click', function( e ) { graph.createMsg(); } );
document.getElementById( 'btn-diversions' ).addEventListener( 'click', function( e ) { graph.showDiversions(); } ); document.getElementById( 'btn-diversions' ).addEventListener( 'click', function( e ) { graph.showDiversions(); } );
document.getElementById( 'btn-audio' ).addEventListener( 'click', function( e ) { graph.showAudioFiles(); } ); document.getElementById( 'btn-audio' ).addEventListener( 'click', function( e ) { graph.showAudioFiles(); } );
@ -1025,6 +1034,20 @@ class Graph {
'value': this.configuration.hasOwnProperty('nothing_text') ? this.configuration.nothing_text : "nothing" 'value': this.configuration.hasOwnProperty('nothing_text') ? this.configuration.nothing_text : "nothing"
}) })
), ),
crel(
'label',
"Timing factor: (< 1 is faster, >1 is slower)",
crel('input', {
'type': 'number',
'on': {
'change': function(e){
panopticon.graph.configuration['time_factor'] = parseFloat(e.target.value)
}
},
'value': this.configuration.hasOwnProperty('time_factor') ? this.configuration.time_factor : 1,
'step': 0.01
})
),
crel('hr'), crel('hr'),
crel('h2', 'Light fade setting #0'), crel('h2', 'Light fade setting #0'),
crel( crel(
@ -1989,10 +2012,14 @@ class Graph {
if(this.getDirectionsFrom( source ).length < 1 && this.getDirectionsFrom( target ).length < 1 && this.getDirectionsTo( target ).length < 1) { if(this.getDirectionsFrom( source ).length < 1 && this.getDirectionsFrom( target ).length < 1 && this.getDirectionsTo( target ).length < 1) {
skipDistances = true; skipDistances = true;
let distance = this.distances[source['@id']]; let distance = this.distances[source['@id']];
if(distance == null) {
skipDistances = false;
} else {
let d = [distance[0] + 1, distance[1]]; let d = [distance[0] + 1, distance[1]];
// create a distance based on source's position // create a distance based on source's position
// this saves us from running the slow calculateDistancesFromStart // this saves us from running the slow calculateDistancesFromStart
this.distances[target['@id']] = d; this.distances[target['@id']] = d;
}
} else { } else {
skipDistances = false; skipDistances = false;
} }
@ -2009,7 +2036,7 @@ class Graph {
createMsg() { createMsg() {
this.addMsg(); this.addMsg();
this.build(); // this.build(); // already happens in addMsg()
} }
createConnectedMsg(sourceMsg) { createConnectedMsg(sourceMsg) {
@ -2150,10 +2177,16 @@ class Graph {
} }
loadData( data, language_code ) { loadData( data, language_code ) {
console.time('load');
this.language_code = language_code; this.language_code = language_code;
this.data = data; this.data = data;
console.time('load:update');
this.updateFromData(); this.updateFromData();
console.timeEnd('load:update');
console.time('load:build');
this.build( true ); this.build( true );
console.timeEnd('load:build');
console.timeEnd('load');
} }
updateFromData(skipDistances) { updateFromData(skipDistances) {
@ -2181,7 +2214,9 @@ class Graph {
} }
// save state; // save state;
this.saveState(); // console.time('update:save')
// this.saveState();
// console.timeEnd('update:save')
} }
updateHugveyStatus(hv) { updateHugveyStatus(hv) {
@ -2205,19 +2240,20 @@ class Graph {
} }
} }
saveState() { // saveState() {
window.localStorage.setItem( "lastState", this.getJsonString() ); // window.localStorage.setItem( "lastState", this.getJsonString() );
} // }
//
hasSavedState() { // hasSavedState() {
return window.localStorage.getItem( "lastState" ) !== null; // return window.localStorage.getItem( "lastState" ) !== null;
} // }
//
loadFromState() { // loadFromState() {
this.loadData( JSON.parse( window.localStorage.getItem( "lastState" ) ) ); // this.loadData( JSON.parse( window.localStorage.getItem( "lastState" ) ) );
} // }
build( isInit ) { build( isInit ) {
console.trace();
this.simulation = d3.forceSimulation( this.messages ) this.simulation = d3.forceSimulation( this.messages )
.force( "link", d3.forceLink( this.directions ).id( d => d['@id'] ).strength(0) ) .force( "link", d3.forceLink( this.directions ).id( d => d['@id'] ).strength(0) )
// .force( "charge", d3.forceManyBody().strength( 100 ) ) // .force( "charge", d3.forceManyBody().strength( 100 ) )
@ -2399,9 +2435,11 @@ class Graph {
// this.simulation.alpha(1); // this.simulation.alpha(1);
// this.simulation.restart(); // this.simulation.restart();
console.time('build:simulate')
for ( let i = 0, n = Math.ceil( Math.log( this.simulation.alphaMin() ) / Math.log( 1 - this.simulation.alphaDecay() ) ); i < n; ++i ) { for ( let i = 0, n = Math.ceil( Math.log( this.simulation.alphaMin() ) / Math.log( 1 - this.simulation.alphaDecay() ) ); i < n; ++i ) {
this.simulation.tick(); this.simulation.tick();
} }
console.timeEnd('build:simulate')
return this.svg.node(); return this.svg.node();
} }
@ -2461,7 +2499,7 @@ class Graph {
} }
i++; i++;
console.log('set for id', childMsgId, goingDown, depth, yPos); // console.log('set for id', childMsgId, goingDown, depth, yPos);
distances[childMsgId] = [depth, yPos]; distances[childMsgId] = [depth, yPos];
} }
@ -2498,26 +2536,26 @@ class Graph {
let yPos = 0; let yPos = 0;
console.time('step1'); console.time('step1');
for(let startMsg of starts) { for(let startMsg of starts) {
console.time('start: '+startMsg['@id']); // console.time('start: '+startMsg['@id']);
if(distances[startMsg['@id']] === null) { if(distances[startMsg['@id']] === null) {
distances[startMsg['@id']] = [0, yPos]; distances[startMsg['@id']] = [0, yPos];
} }
yPos = traverseMsg(startMsg['@id'], 1 , true, yPos); yPos = traverseMsg(startMsg['@id'], 1 , true, yPos);
yPos += 1; yPos += 1;
console.timeEnd('start: '+startMsg['@id']); // console.timeEnd('start: '+startMsg['@id']);
} }
console.timeEnd('step1'); console.timeEnd('step1');
console.time('step2'); console.time('step2');
// now we have the formal tree, lets try to polish the rest: // now we have the formal tree, lets try to polish the rest:
for(let msgId in distances) { for(let msgId in distances) {
console.time('polish: '+ msgId); // console.time('polish: '+ msgId);
if(distances[msgId] === null) { if(distances[msgId] === null) {
continue; continue;
} }
// let's see if there are parent nodes that are not in the distances array // let's see if there are parent nodes that are not in the distances array
// traverse up and see whether we encounter anything new // traverse up and see whether we encounter anything new
traverseMsg(msgId, distances[msgId][0] -1, false, distances[msgId][1]) traverseMsg(msgId, distances[msgId][0] -1, false, distances[msgId][1])
console.timeEnd('polish: '+ msgId); // console.timeEnd('polish: '+ msgId);
} }
console.timeEnd('step2'); console.timeEnd('step2');

View file

@ -59,6 +59,18 @@ body.dark{
} }
} }
.btn.loading:after {
display:inline-block;
content: '';
width: 15px;
height: 15px;
background-color: white;
border-radius: 100%;
-webkit-animation: sk-scaleout 1.0s infinite ease-in-out;
animation: sk-scaleout 1.0s infinite ease-in-out;
}
input[type="number"] { input[type="number"] {
width: 80px; width: 80px;
text-align:right; text-align:right;
@ -122,18 +134,6 @@ img.icon{
color:#ccc; color:#ccc;
list-style: none;padding:0; list-style: none;padding:0;
.loading:after {
display:inline-block;
content: '';
width: 15px;
height: 15px;
background-color: white;
border-radius: 100%;
-webkit-animation: sk-scaleout 1.0s infinite ease-in-out;
animation: sk-scaleout 1.0s infinite ease-in-out;
}
} }
} }
} }