diff --git a/hugvey/central_command.py b/hugvey/central_command.py index 17cd9cb..9e47f74 100644 --- a/hugvey/central_command.py +++ b/hugvey/central_command.py @@ -134,6 +134,8 @@ class CentralCommand(object): 'languages': self.config['languages'], 'hugvey_ids': self.hugvey_ids, 'hugveys': [], + 'logbookId': None, + 'logbook': [], } #use this to test if any threads stay open @@ -143,6 +145,11 @@ class CentralCommand(object): for hv_id in self.hugvey_ids: status['hugveys'].append(self.getHugveyStatus(hv_id, selected_id == hv_id)) + if selected_id and selected_id in self.hugveys: + if self.hugveys[selected_id].recorder: + status['logbook'] = self.hugveys[selected_id].recorder.currentLog + status['logbookId'] = selected_id + return status def commandHugvey(self, hv_id, msg): diff --git a/hugvey/speech/recorder.py b/hugvey/speech/recorder.py index 8427ed8..e0eed63 100644 --- a/hugvey/speech/recorder.py +++ b/hugvey/speech/recorder.py @@ -27,6 +27,7 @@ class Recorder: self.main_folder = out_folder # unfortunately not every device plays 16kHz audio streams self.running = False self.data = array('h') + self.currentLog = [] def start(self): self.subsequentMutedFrames = 0 @@ -34,6 +35,7 @@ class Recorder: self.data = array('h') self.currentTranscription = "" + self.currentLog = [] t = time.strftime("%Y%m%d-%H:%M:%S") @@ -105,7 +107,8 @@ class Recorder: def updateTranscription(self, text): self.currentTranscription = text - def log(self, origin, msg): + def log(self, origin, msg, extra=None): + self.currentLog.append({'time':time.time(), 'origin': origin, 'msg': msg, 'extra': extra}) with open(os.path.join(self.out_folder, "log.txt"), "a") as fp: fp.write(f"{origin}: {msg}\n") diff --git a/hugvey/story.py b/hugvey/story.py index cee4b90..3f19c32 100644 --- a/hugvey/story.py +++ b/hugvey/story.py @@ -251,6 +251,7 @@ class Condition(object): self.method = None self.type = None self.vars = {} + self.logInfo = None @classmethod def initFromJson(conditionClass, data, story): @@ -303,6 +304,7 @@ class Condition(object): story.stats['silentTimeouts'] +=1 story.stats['consecutiveSilentTimeouts'] += 1 + self.logInfo = "{}s".format(self.vars['seconds']) return True def _hasVariable(self, story) -> bool: @@ -316,7 +318,10 @@ class Condition(object): if 'notSet' in self.vars and self.vars['notSet']: # inverse: r = not r - + self.logInfo = "Does {} have variable {}".format( + 'not' if 'notSet' in self.vars and self.vars['notSet'] else '', + self.vars['variable'] + ) return r def _hasDiverged(self, story) -> bool: @@ -334,7 +339,12 @@ class Condition(object): if 'inverseMatch' in self.vars and self.vars['inverseMatch']: # inverse: r = not r - + + self.logInfo = "Has {} diverged to {}".format( + 'not' if 'inverseMatch' in self.vars and self.vars['inverseMatch'] else '', + self.vars['diversionId'] + ) + return r def _hasMetReplyContains(self, story) -> bool: @@ -373,6 +383,10 @@ class Condition(object): if 'instantMatch' in self.vars and self.vars['instantMatch']: story.logger.info(f"Instant match on {self.vars['regex']}, {self.vars}") + self.logInfo = "Instant match of {}, captured {}".format( + self.vars['regex'], + capturedVariables + ) return True # TODO: implement 'instant match' -> don't wait for isFinished() @@ -395,7 +409,11 @@ class Condition(object): if capturedVariables is not None: for captureGroup in capturedVariables: story.setVariableValue(captureGroup, capturedVariables[captureGroup]) - + self.logInfo = "Match of {}, captured {} after, {}".format( + self.vars['regex'], + capturedVariables, + timeSinceReply + ) return True break # don't check other delays # wait for delay to match @@ -408,6 +426,7 @@ class Condition(object): return False # There is a match and no delay say, person finished speaking. Go ahead sir! + self.logInfo = "Match" return True def getLogSummary(self): @@ -1067,6 +1086,14 @@ class Story(object): def addToLog(self, node): self.log.append((node, self.timer.getElapsed())) + + if self.hugvey.recorder: + if isinstance(node, Message): + self.hugvey.recorder.log('hugvey', node.text, node.id) + if isinstance(node, Diversion): + self.hugvey.recorder.log('diversion',node.id) + if isinstance(node, Condition): + self.hugvey.recorder.log('condition',node.logInfo, node.id) async def _renderer(self): """ @@ -1143,8 +1170,6 @@ class Story(object): message.id, message.text)) self.addToLog(message) self.hugvey.eventLogger.info(f"message: {message.id} {message.uuid} start \"{message.text}\"") - if self.hugvey.recorder: - self.hugvey.recorder.log('h',message.text) # TODO: prep events & timer etc. fn = await message.getAudioFilePath() diff --git a/www/css/styles.css b/www/css/styles.css index baaf91a..1e03e23 100644 --- a/www/css/styles.css +++ b/www/css/styles.css @@ -59,6 +59,8 @@ img.icon { width: 380px; height: 100%; overflow-y: scroll; } + .panopticon #status { + width: 50%; } #status > div { width: 33.3333333%; height: 200px; @@ -66,7 +68,7 @@ img.icon { box-sizing: border-box; position: relative; } #status > div#overview { - width: 66.66667%; } + width: 100% / 3; } #status .counts dd, #status .counts dt { display: inline-block; width: 30px; @@ -80,7 +82,11 @@ img.icon { color: white; display: flex; flex-direction: column; - justify-content: center; } + justify-content: center; + width: 120px; + flex-grow: 1; } + .panopticon #status .hugvey { + width: 160px; } #status .hugvey h1 { text-align: center; margin: 0; @@ -304,3 +310,17 @@ body.showTimeline #toggleTimeline { border-color: green; } #timeline .vis-text, #timeline .vis-labelset .vis-label { color: #999; } + +#logbook { + width: 50%; + padding: 10px; + color: #999; } + #logbook .log { + margin-bottom: 10px; } + #logbook .time { + color: #666; } + #logbook .content .origin { + padding-right: 10px; + color: orange; } + #logbook .content .extra { + color: #555; } diff --git a/www/js/hugvey_console.js b/www/js/hugvey_console.js index 463db90..46c8f3d 100644 --- a/www/js/hugvey_console.js +++ b/www/js/hugvey_console.js @@ -13,6 +13,7 @@ class Panopticon { languages: [], hugveys: [], selectedId: null, + logbook: "", }, methods: { time_passed: function( hugvey, property ) { @@ -21,6 +22,9 @@ class Panopticon { timer: function(hugvey, property) { return panopticon.stringToHHMMSS( hugvey[property] ); }, + formatted: function(time) { + return moment(time).utc().format("hh:mm:ss"); + }, loadNarrative: function( code, file ) { panopticon.hugveys.selectedId = null; @@ -58,6 +62,8 @@ class Panopticon { }, showHugvey: function(hv) { panopticon.hugveys.selectedId = hv.language ? hv.id : null; + panopticon.hugveys.logbook = []; + panopticon.hugveys.logbookId = null; panopticon.updateSelectedHugvey(); } } @@ -109,6 +115,8 @@ class Panopticon { this.hugveys.languages = msg['languages']; this.languages = msg['languages']; this.hugveys.hugveys = msg['hugveys']; + this.hugveys.logbook = msg['logbook']; + this.hugveys.logbookId = msg['logbookId']; if(this.hugveys.selectedId) { this.updateSelectedHugvey(); } diff --git a/www/panopticon.html b/www/panopticon.html index 1c4a56c..3c6610c 100644 --- a/www/panopticon.html +++ b/www/panopticon.html @@ -20,13 +20,6 @@
Uptime
{{uptime}}
- -
Finish
Pause
Resume
+
+ {{ hv.light }} +
-
+
+
+

Log of {{logbookId}}

+
+
{{formatted(log.time)}}
+
+ {{log.origin}} + {{log.msg}} + ( {{log.extra}} ) +
+
+
diff --git a/www/scss/styles.scss b/www/scss/styles.scss index a0c2770..4db188e 100644 --- a/www/scss/styles.scss +++ b/www/scss/styles.scss @@ -82,6 +82,10 @@ img.icon{ height: 100%; overflow-y: scroll; + .panopticon &{ + width: 50% + } + & > div{ width: 33.3333333%; height: 200px; @@ -90,7 +94,7 @@ img.icon{ position: relative; &#overview{ - width: 100% / 3 * 2; + width: 100% / 3; } } @@ -113,6 +117,12 @@ img.icon{ display: flex; flex-direction: column; justify-content: center; + width: 120px; + flex-grow: 1; + + .panopticon & { + width: 160px; + } h1{ text-align: center; @@ -492,3 +502,24 @@ img.icon{ } } + +#logbook{ + width: 50%; + padding: 10px; + color: #999; + .log{ + margin-bottom:10px; + } + .time{ + color:#666; + } + .content{ + .origin{ + padding-right: 10px; + color:orange; + } + .extra{ + color:#555; + } + } +} \ No newline at end of file