diff --git a/hugvey/central_command.py b/hugvey/central_command.py index e69cec2..19d8d1f 100644 --- a/hugvey/central_command.py +++ b/hugvey/central_command.py @@ -590,7 +590,7 @@ class HugveyState(object): else: if self.story is None: return - + if event['reloadStory']: self.startMsgId = event['msg_id'] self.logger.debug(f"Restart from {self.startMsgId}") @@ -723,7 +723,7 @@ class HugveyState(object): else: # new story instance on each run port = self.command.config['web']['port'] - + resuming = False if Story.hugveyHasSavedState(self.id): self.logger.info(f"Recovering from state :-)") @@ -735,20 +735,20 @@ class HugveyState(object): else: self.story = Story(self, port) self.story.setStoryData(copy.deepcopy(self.command.languages[self.language_code]), self.language_code) - - + + if not self.streamer: await asyncio.sleep(1) self.streamer.triggerStart() - + startMsgId = self.startMsgId - self.startMsgId = None # use only once, reset before 'run' + self.startMsgId = None # use only once, reset before 'run' if not startMsgId and self.story.currentMessage: startMsgId = self.story.currentMessage.id - + self.logger.info(f"Starting from {startMsgId}") - + self.setLightStatus(False) await self.story.run(startMsgId, resuming) @@ -774,7 +774,9 @@ class HugveyState(object): if self.command.config['voice']['record_dir']: self.logger.warn("Record Audio of conversation") self.recorder = Recorder( self.id, - self.command.config['voice']['src_rate'], self.command.config['voice']['record_dir']) + self.command.config['voice']['src_rate'], self.command.config['voice']['record_dir'], + self.command.config['voice']['record_voice'] if 'record_voice' in self.command.config['voice'] else False) + self.streamer.addConsumer(self.recorder) self.logger.debug("Start Speech") diff --git a/hugvey/speech/recorder.py b/hugvey/speech/recorder.py index 9619dd5..97695ac 100644 --- a/hugvey/speech/recorder.py +++ b/hugvey/speech/recorder.py @@ -16,9 +16,9 @@ class Recorder: Record the streamed audio """ - def __init__(self, hv_id, src_rate, out_folder): + def __init__(self, hv_id, src_rate, out_folder, record_voice = True): self.logger = mainLogger.getChild(f"{hv_id}").getChild('recorder') - + if not os.path.exists(out_folder): raise Exception(f"Invalid output folder for recordings: {out_folder}") @@ -26,62 +26,69 @@ class Recorder: self.src_rate = src_rate self.main_folder = out_folder # unfortunately not every device plays 16kHz audio streams self.running = False + self.record_voice = record_voice self.data = array('h') self.currentLog = [] - + def start(self): self.subsequentMutedFrames = 0 self.fragmentNr = 0 - + self.data = array('h') self.currentTranscription = "" self.currentLog = [] - + day = time.strftime("%Y%m%d") t = time.strftime("%H:%M:%S") - + self.out_folder = os.path.join(self.main_folder, day, f"{self.hv_id}", t) if not os.path.exists(self.out_folder): self.logger.debug(f"Create directory {self.out_folder}") self.target_folder = os.makedirs(self.out_folder, exist_ok=True) - + self.running = True - - + + def writeData(self): if len(self.data) < 1: self.logger.info("Skip empty wave creation") return - - self.fragmentNr += 1 - - fn = os.path.join(self.out_folder, f"{self.fragmentNr}.wav") - - self.logger.info(f"Write wave: {fn}") - - self.wf = wave.open(fn, 'wb') - self.wf.setnchannels(1) - self.wf.setsampwidth(2) - self.wf.setframerate(self.src_rate) - # adapted from https://stackoverflow.com/questions/892199/detect-record-audio-in-python#6743593 - self.wf.writeframes(pack('<' + ('h'*len(self.data)), *self.data)) - self.wf.close() - - with open(os.path.join(self.out_folder, "transcriptions.txt"), "a") as fp: - fp.write(f"{self.fragmentNr}\t{self.currentTranscription}\n") + + + if self.record_voice: + self.fragmentNr += 1 + + fn = os.path.join(self.out_folder, f"{self.fragmentNr}.wav") + + self.logger.info(f"Write wave: {fn}") + + self.wf = wave.open(fn, 'wb') + self.wf.setnchannels(1) + self.wf.setsampwidth(2) + self.wf.setframerate(self.src_rate) + # adapted from https://stackoverflow.com/questions/892199/detect-record-audio-in-python#6743593 + self.wf.writeframes(pack('<' + ('h'*len(self.data)), *self.data)) + self.wf.close() + + with open(os.path.join(self.out_folder, "transcriptions.txt"), "a") as fp: + fp.write(f"{self.fragmentNr}\t{self.currentTranscription}\n") + self.log('-',self.currentTranscription) - + self.data = array('h') self.currentTranscription = "" - + def receive(self, chunk): + if not self.record_voice: + return + if not self.running: - return - + return + # self.logger.debug('receive {}'.format(len(chunk))) if audioop.max(chunk, 2) == 0: # mic is muted on client side. - + self.subsequentMutedFrames += 1 #self.logger.debug(f"Empty frame {self.subsequentMutedFrames}") if self.subsequentMutedFrames == 4: @@ -92,27 +99,27 @@ class Recorder: return else: self.subsequentMutedFrames = 0 - + d = array('h', chunk) self.data.extend(d) # self.wf.writeframes(chunk) - + def shutdown(self): self.writeData() self.running = False # self.wf.close() - + def triggerStart(self): self.start() def updateTranscription(self, text): self.currentTranscription = text - + 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") - - + + def __del__(self): - self.logger.warn("Destroyed recorder object") \ No newline at end of file + self.logger.warn("Destroyed recorder object") diff --git a/server_config.yml b/server_config.yml index 1523212..f579c27 100644 --- a/server_config.yml +++ b/server_config.yml @@ -7,6 +7,8 @@ voice: port: 4444 chunk: 2972 google_credentials: "../test_googlespeech/My First Project-0c7833e0d5fa.json" + record_dir: "./recordings" + record_voice: false hugveys: 26 languages: - code: en-GB diff --git a/www/js/crel.min.js b/www/js/crel.min.js index f451ebb..25d8e2e 100644 --- a/www/js/crel.min.js +++ b/www/js/crel.min.js @@ -5,19 +5,27 @@ crel.attrMap['on'] = function(element, value) { element.addEventListener(eventName, value[eventName]); } }; -crel.attrMap['options'] = function(element, values) { +crel.attrMap['options'] = function(element, values, a, b) { if(element.tagName != "SELECT") { return; } - console.log(values, element.value); + if(Array.isArray(values)) { for (let option of values) { - element.appendChild(crel('option', option)); + if(element.value == option) { + element.appendChild(crel('option', {'selected': 'selected'}, option)); + } else { + element.appendChild(crel('option', option)); + } } } else { for (let option in values) { - element.appendChild(crel('option', {'value': option}, values[option])); + if(element.value == option) { + element.appendChild(crel('option', {'selected': 'selected','value': option}, values[option])); + }else{ + element.appendChild(crel('option', {'value': option}, values[option])); + } } } - -}; \ No newline at end of file + +}; diff --git a/www/js/hugvey_timeline.js b/www/js/hugvey_timeline.js index bc00d36..786303d 100644 --- a/www/js/hugvey_timeline.js +++ b/www/js/hugvey_timeline.js @@ -28,6 +28,7 @@ class Timeline{ this.dataGroups = new vis.DataSet(groups); let options = { maxHeight: '100%', + height: '100%', margin : { item: { horizontal: 0, @@ -90,7 +91,7 @@ checkbox.addEventListener('change', (event) => { console.error( "not a valid message: " + e.data ); return; } - + if(msg['action'] == 'status') { for(let hv of msg['hugveys']){ console.log(hv['language'], hv['status']);