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:
# 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:
return False
@ -575,7 +575,7 @@ class Condition(object):
if replyDuration > float(delay['minReplyDuration']):
timeSinceReply = r.getTimeSinceLastUtterance()
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 capturedVariables is not None:
for captureGroup in capturedVariables:
@ -585,7 +585,7 @@ class Condition(object):
capturedVariables,
timeSinceReply
)
self.usedContainsDuration = float(delay['waitTime'])
self.usedContainsDuration = story.applyTimeFactor(delay['waitTime'])
return True
break # don't check other delays
# 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
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()
if timeSince < 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.
# 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
if story.currentMessage.didRepeat:
@ -1025,12 +1025,12 @@ class Diversion(object):
return
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
return
interval = float(self.params['interval'])
interval = story.applyTimeFactor(self.params['interval'])
if not self.params['fromLastMessage']:
# (1) last spoken at all
@ -1115,6 +1115,7 @@ class Configuration(object):
id = 'configuration'
volume = 1 # Volume multiplier for 'play' command
nothing_text = "nothing" # When variable is not set, but used in sentence, replace it with this word.
time_factor = 1
light0_intensity = 0
light0_fade = 30. # fade duration in seconds
light1_intensity = 150
@ -1954,6 +1955,15 @@ class Story(object):
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):
"""
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 {
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"] {
width: 80px;
text-align: right; }
@ -91,15 +101,6 @@ img.icon {
color: #ccc;
list-style: none;
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 {
display: inline-block;
width: 30px;

View file

@ -324,7 +324,16 @@ class Graph {
this.linkG = this.container.append( "g" )
.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-diversions' ).addEventListener( 'click', function( e ) { graph.showDiversions(); } );
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"
})
),
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('h2', 'Light fade setting #0'),
crel(
@ -1989,10 +2012,14 @@ class Graph {
if(this.getDirectionsFrom( source ).length < 1 && this.getDirectionsFrom( target ).length < 1 && this.getDirectionsTo( target ).length < 1) {
skipDistances = true;
let distance = this.distances[source['@id']];
let d = [distance[0] + 1, distance[1]];
// create a distance based on source's position
// this saves us from running the slow calculateDistancesFromStart
this.distances[target['@id']] = d;
if(distance == null) {
skipDistances = false;
} else {
let d = [distance[0] + 1, distance[1]];
// create a distance based on source's position
// this saves us from running the slow calculateDistancesFromStart
this.distances[target['@id']] = d;
}
} else {
skipDistances = false;
}
@ -2009,7 +2036,7 @@ class Graph {
createMsg() {
this.addMsg();
this.build();
// this.build(); // already happens in addMsg()
}
createConnectedMsg(sourceMsg) {
@ -2150,10 +2177,16 @@ class Graph {
}
loadData( data, language_code ) {
console.time('load');
this.language_code = language_code;
this.data = data;
console.time('load:update');
this.updateFromData();
console.timeEnd('load:update');
console.time('load:build');
this.build( true );
console.timeEnd('load:build');
console.timeEnd('load');
}
updateFromData(skipDistances) {
@ -2181,7 +2214,9 @@ class Graph {
}
// save state;
this.saveState();
// console.time('update:save')
// this.saveState();
// console.timeEnd('update:save')
}
updateHugveyStatus(hv) {
@ -2205,19 +2240,20 @@ class Graph {
}
}
saveState() {
window.localStorage.setItem( "lastState", this.getJsonString() );
}
hasSavedState() {
return window.localStorage.getItem( "lastState" ) !== null;
}
loadFromState() {
this.loadData( JSON.parse( window.localStorage.getItem( "lastState" ) ) );
}
// saveState() {
// window.localStorage.setItem( "lastState", this.getJsonString() );
// }
//
// hasSavedState() {
// return window.localStorage.getItem( "lastState" ) !== null;
// }
//
// loadFromState() {
// this.loadData( JSON.parse( window.localStorage.getItem( "lastState" ) ) );
// }
build( isInit ) {
console.trace();
this.simulation = d3.forceSimulation( this.messages )
.force( "link", d3.forceLink( this.directions ).id( d => d['@id'] ).strength(0) )
// .force( "charge", d3.forceManyBody().strength( 100 ) )
@ -2399,9 +2435,11 @@ class Graph {
// this.simulation.alpha(1);
// 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 ) {
this.simulation.tick();
}
console.timeEnd('build:simulate')
return this.svg.node();
}
@ -2461,7 +2499,7 @@ class Graph {
}
i++;
console.log('set for id', childMsgId, goingDown, depth, yPos);
// console.log('set for id', childMsgId, goingDown, depth, yPos);
distances[childMsgId] = [depth, yPos];
}
@ -2498,26 +2536,26 @@ class Graph {
let yPos = 0;
console.time('step1');
for(let startMsg of starts) {
console.time('start: '+startMsg['@id']);
// console.time('start: '+startMsg['@id']);
if(distances[startMsg['@id']] === null) {
distances[startMsg['@id']] = [0, yPos];
}
yPos = traverseMsg(startMsg['@id'], 1 , true, yPos);
yPos += 1;
console.timeEnd('start: '+startMsg['@id']);
// console.timeEnd('start: '+startMsg['@id']);
}
console.timeEnd('step1');
console.time('step2');
// now we have the formal tree, lets try to polish the rest:
for(let msgId in distances) {
console.time('polish: '+ msgId);
// console.time('polish: '+ msgId);
if(distances[msgId] === null) {
continue;
}
// let's see if there are parent nodes that are not in the distances array
// traverse up and see whether we encounter anything new
traverseMsg(msgId, distances[msgId][0] -1, false, distances[msgId][1])
console.timeEnd('polish: '+ msgId);
// console.timeEnd('polish: '+ msgId);
}
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"] {
width: 80px;
text-align:right;
@ -122,18 +134,6 @@ img.icon{
color:#ccc;
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;
}
}
}
}