From d00b676ad8b032ce442fef3ce264ce17be6284c9 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Fri, 25 Jan 2019 14:10:19 +0100 Subject: [PATCH] Show progress for selected Hugvey --- hugvey/central_command.py | 4 +-- hugvey/story.py | 65 +++++++++++++++++++++++++++++---------- www/css/styles.css | 5 +++ www/index.html | 10 +++--- www/js/hugvey_console.js | 46 +++++++++++++++++++++++++-- www/scss/styles.scss | 10 ++++++ 6 files changed, 115 insertions(+), 25 deletions(-) diff --git a/hugvey/central_command.py b/hugvey/central_command.py index 81a95e2..f3fa4e4 100644 --- a/hugvey/central_command.py +++ b/hugvey/central_command.py @@ -91,9 +91,9 @@ class CentralCommand(object): status['status'] = hv.getStatus() status['language'] = hv.language_code status['msg'] = hv.story.currentMessage.id if hv.story.currentMessage else None - status['counts'] = hv.story.getStoryCounts() status['finished'] = hv.story.isFinished() - + status['history'] = hv.story.getLogSummary() + status['counts'] = {t: len(a) for t, a in status['history'].items() } return status diff --git a/hugvey/story.py b/hugvey/story.py index bb893d1..68a81e6 100644 --- a/hugvey/story.py +++ b/hugvey/story.py @@ -13,6 +13,7 @@ class Message(object): self.text = text self.isStart = False self.reply = None + self.replyTime = None self.audioFile= None @classmethod @@ -23,8 +24,9 @@ class Message(object): msg.audioFile = data['audio']['file'] return msg - def setReply(self, text): + def setReply(self, text, replyTime): self.reply = text + self.replyTime = replyTime def hasReply(self): return self.reply is not None @@ -36,6 +38,13 @@ class Message(object): return self.reply + def getLogSummary(self): + return { + 'id': self.id, + 'time': self.replyTime, + 'replyText': self.reply + } + class Condition(object): """ @@ -97,7 +106,11 @@ class Condition(object): if self.vars['contains'] == '*': return True return self.vars['contains'] in story.currentMessage.getReply() - + + def getLogSummary(self): + return { + 'id': self.id + } class Direction(object): """ @@ -109,9 +122,13 @@ class Direction(object): self.msgFrom = msgFrom self.msgTo = msgTo self.conditions = [] + self.conditionMet = None def addCondition(self, condition: Condition): self.conditions.append(condition) + + def setMetCondition(self, condition: Condition): + self.conditionMet = condition @classmethod def initFromJson(direction, data, story): @@ -123,6 +140,12 @@ class Direction(object): c = story.get(conditionId) direction.addCondition(c) return direction + + def getLogSummary(self): + return { + 'id': self.id, + 'condition': self.conditionMet.id if self.conditionMet else None + } class Diversion(object): @@ -145,6 +168,13 @@ class Diversion(object): c = story.get(conditionId) diversion.addCondition(c) return diversion + + + def getLogSummary(self): + return { + 'id': self.id, +# 'time': self.replyTime + } storyClasses = { @@ -224,18 +254,15 @@ class Story(object): logger.debug('resume hugvey') self.timer.resume() - def getStoryCounts(self): -# counts = {} -# for item in self.log: -# n =item.__class__.__name__ -# if n not in counts: -# counts[n] = 0 -# counts[n] += 1 -# return counts - return { - 'messages': len([e for e in self.log if isinstance(e, Message)]), - 'diversions': len([e for e in self.log if isinstance(e, Diversion)]) + def getLogSummary(self): + summary = { + # e[0]: the entity, e[1]: the logged time + 'messages': [(e[0].getLogSummary(), e[1]) for e in self.log if isinstance(e[0], Message)], + 'directions': [(e[0].getLogSummary(), e[1]) for e in self.log if isinstance(e[0], Direction)], + 'diversions': [(e[0].getLogSummary(), e[1]) for e in self.log if isinstance(e[0], Diversion)], } +# print(self.log) + return summary def setStoryData(self, story_data): """ @@ -347,7 +374,7 @@ class Story(object): if e['is_final']: # final result self.lastSpeechEndTime = e['time'] - self.currentMessage.setReply(e['transcript']) + self.currentMessage.setReply(e['transcript'], self.timer.getElapsed()) def _processDirections(self, directions): for direction in directions: @@ -355,10 +382,14 @@ class Story(object): if condition.isMet(self): logger.info("Condition is met: {0}, going to {1}".format( condition.id, direction.msgTo.id)) - self.log.append(condition) - self.log.append(direction) + direction.setMetCondition(condition) + self.addToLog(condition) + self.addToLog(direction) self.setCurrentMessage(direction.msgTo) return direction + + def addToLog(self, node): + self.log.append((node, self.timer.getElapsed())) async def _renderer(self): """ @@ -400,7 +431,7 @@ class Story(object): logger.info("Current message: ({0}) \"{1}\"".format( message.id, message.text)) - self.log.append(message) + self.addToLog(message) # TODO: prep events & timer etc. if message.audioFile: self.hugvey.sendCommand({ diff --git a/www/css/styles.css b/www/css/styles.css index 06f6332..b4bec5b 100644 --- a/www/css/styles.css +++ b/www/css/styles.css @@ -101,6 +101,11 @@ img.icon { cursor: grab; } #story svg#graph:active { cursor: grabbing; } + #story svg#graph .beenHit circle { + stroke: #0f0; + stroke-width: 2px; } + #story svg#graph line.beenHit { + stroke: #0f0; } #story circle { cursor: pointer; fill: #77618e; } diff --git a/www/index.html b/www/index.html index 2b2360d..620f4d8 100644 --- a/www/index.html +++ b/www/index.html @@ -28,7 +28,9 @@
+ :class="[{'hugvey--on': hv.status != 'off'},'hugvey--' + hv.status]" + @click="showHugvey(hv)" + >

{{ hv.id }}

@@ -54,9 +56,9 @@ {{ hv.msg }}
-
Pause
-
Resume
-
Restart
+
Pause
+
Resume
+
Restart
diff --git a/www/js/hugvey_console.js b/www/js/hugvey_console.js index a622424..6fd4dc6 100644 --- a/www/js/hugvey_console.js +++ b/www/js/hugvey_console.js @@ -4,6 +4,7 @@ class Panopticon { constructor() { console.log( "Init panopticon" ); this.languages = [] + this.selectedHugvey = null; this.hugveys = new Vue( { el: "#status", data: { @@ -37,6 +38,10 @@ class Panopticon { change_lang: function(hv, lang_code) { hv.status = "loading"; return panopticon.change_language(hv.id, lang_code); + }, + showHugvey: function(hv) { + panopticon.selectedHugvey = hv.id; + panopticon.updateSelectedHugvey(); } } } ); @@ -73,10 +78,34 @@ class Panopticon { this.hugveys.languages = msg['languages']; this.languages = msg['languages']; this.hugveys.hugveys = msg['hugveys']; + if(this.selectedHugvey) { + this.updateSelectedHugvey(); + } break; } } ); } + + updateSelectedHugvey() { + if(! this.selectedHugvey) { + return; + } + console.log('showNOW', this.selectedHugvey); + let hv = this.getHugvey(this.selectedHugvey); + if(this.graph.language_code != hv.language) { + this.loadNarrative(hv.language); + } + this.graph.updateHugveyStatus(hv); + } + + getHugvey(id) { + for(let hv of this.hugveys.hugveys) { + if(hv.id == id) { + return hv; + } + } + return null; + } send( msg ) { if ( this.socket.readyState == WebSocket.OPEN ) { @@ -129,10 +158,10 @@ class Panopticon { this.send( { action: 'resume', hugvey: hv_id } ) } pause( hv_id ) { - this.send( { action: 'play', hugvey: hv_id } ) + this.send( { action: 'pause', hugvey: hv_id } ) } restart( hv_id ) { - this.send( { action: 'restart', hugvey: hv_id } ) + this.send( { action: 'restart', hugvey: hv_id } ); } change_language( hv_id, lang_code ) { this.send( { action: 'change_language', hugvey: hv_id, lang_code: lang_code } ); @@ -717,6 +746,19 @@ class Graph { // save state; this.saveState(); } + + updateHugveyStatus(hv) { + let els = document.getElementsByClassName('beenHit'); + while(els.length > 0) { + els[0].classList.remove('beenHit'); + } + for(let msg of hv['history']['messages']) { + document.getElementById(msg[0]['id']).classList.add('beenHit'); + } + for(let msg of hv['history']['directions']) { + document.getElementById(msg[0]['id']).classList.add('beenHit'); + } + } saveState() { window.localStorage.setItem( "lastState", this.getJsonString() ); diff --git a/www/scss/styles.scss b/www/scss/styles.scss index 0ae32d5..7b8d745 100644 --- a/www/scss/styles.scss +++ b/www/scss/styles.scss @@ -177,6 +177,16 @@ img.icon{ &:active{ cursor: grabbing; } + + .beenHit{ + circle { + stroke: #0f0; + stroke-width: 2px; + } + } + line.beenHit { + stroke: #0f0; + } } circle{