From ace03099d56393ab9518d068224a691758a74cda Mon Sep 17 00:00:00 2001 From: Thorsten Mueller Date: Thu, 8 Jul 2021 19:32:55 +0200 Subject: [PATCH 1/5] Added feature to skip a phrase on a recording session. --- backend/app/api.py | 50 ++++++++++++++++++++++---------------- backend/app/db.py | 14 +++++++++++ backend/app/file_system.py | 11 +++++++++ frontend/src/App/Record.js | 27 +++++++++++++++++++- 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/backend/app/api.py b/backend/app/api.py index d1f2ca9..006da7e 100644 --- a/backend/app/api.py +++ b/backend/app/api.py @@ -33,31 +33,39 @@ class AudioAPI: def save_audio(self, audio: bytes, uuid: str, prompt: str): user_audio_dir = AudioFS.get_audio_path(uuid) - os.makedirs(user_audio_dir, exist_ok=True) - wav_file_id = AudioFS.create_file_name(prompt) - path = os.path.join(user_audio_dir, wav_file_id) + + if prompt[0:13] == "___SKIPPED___": + res = DB.skipPhrase(uuid) - try: - # save wav file. This step is needed before trimming. - AudioFS.save_audio(path, audio) - AudioFS.save_meta_data(user_audio_dir, uuid, wav_file_id, prompt) + # Save skipped phrase to textfile + AudioFS.save_skipped_data(user_audio_dir,uuid,prompt) + return response(True) + else: + os.makedirs(user_audio_dir, exist_ok=True) + wav_file_id = AudioFS.create_file_name(prompt) + path = os.path.join(user_audio_dir, wav_file_id) - # trim silence and save - trimmed_sound = Audio.trim_silence(path) - Audio.save_audio(path, trimmed_sound) + try: + # save wav file. This step is needed before trimming. + AudioFS.save_audio(path, audio) + AudioFS.save_meta_data(user_audio_dir, uuid, wav_file_id, prompt) - res = DB.save_audio(wav_file_id, prompt, 'english', uuid) - if res.success: - audio_len = Audio.get_audio_len(trimmed_sound) - char_len = len(prompt) - res = DB.update_user_metrics(uuid, audio_len, char_len) + # trim silence and save + trimmed_sound = Audio.trim_silence(path) + Audio.save_audio(path, trimmed_sound) + + res = DB.save_audio(wav_file_id, prompt, 'english', uuid) if res.success: - return response(True) - return response(False) - except Exception as e: - # TODO: log Exception - print(e) - return response(False) + audio_len = Audio.get_audio_len(trimmed_sound) + char_len = len(prompt) + res = DB.update_user_metrics(uuid, audio_len, char_len) + if res.success: + return response(True) + return response(False) + except Exception as e: + # TODO: log Exception + print(e) + return response(False) def get_audio_len(self, audio: bytes): try: diff --git a/backend/app/db.py b/backend/app/db.py index 82a9070..f41f423 100644 --- a/backend/app/db.py +++ b/backend/app/db.py @@ -124,6 +124,20 @@ def update_user_metrics(uuid: str, time: float, char_len: int) -> response: print(e) response(False) + @staticmethod + def skipPhrase(uuid: str) -> response: + try: + query = UserModel \ + .update( + prompt_num=UserModel.prompt_num + 1, + ) \ + .where(uuid == uuid) + query.execute() + return response(True) + except Exception as e: + print(e) + response(False) + @staticmethod def save_audio(audio_id: str, prompt: str, language: str, uuid: str) -> response: diff --git a/backend/app/file_system.py b/backend/app/file_system.py index 838de55..db80ca6 100644 --- a/backend/app/file_system.py +++ b/backend/app/file_system.py @@ -39,8 +39,10 @@ class AudioFS: @staticmethod def save_audio(path: str, audio: bytes): webm_file_name = path + ".webm" + with open(webm_file_name, 'wb+') as f: f.write(audio) + subprocess.call( 'ffmpeg -i {} -ab 160k -ac 2 -ar 44100 -vn {}.wav -y'.format( webm_file_name, path @@ -65,6 +67,15 @@ def save_meta_data(user_audio_dir, uuid, wav_file_id, prompt): with open(path, 'a') as f: f.write(data) + @staticmethod + def save_skipped_data(user_audio_dir, uuid, prompt): + path = os.path.join(user_audio_dir, '%s-skipped.txt' % uuid) + data = "{}\n".format(prompt[13:len(prompt)+13]) + + with open(path, 'a') as f: + f.write(data) + + @staticmethod def get_audio_path(uuid: str) -> str: return os.path.join(audio_dir, uuid) diff --git a/frontend/src/App/Record.js b/frontend/src/App/Record.js index cbb2587..26e3d29 100644 --- a/frontend/src/App/Record.js +++ b/frontend/src/App/Record.js @@ -81,7 +81,7 @@ class Record extends Component {
{this.state.shouldRecord ? "Read Now [Esc] to cancel" - : "[Spacebar] to Start Recording [R] to review [->] for next"} + : "[Spacebar] to Start Recording [R] to review [S] to skip [->] for next"}
{ + // prompt_num in DB um 1 erhöhen und Textfile -skipped.txt anlegen und Sätze dort protokollieren + postAudio("", "___SKIPPED___" + this.state.prompt, this.uuid) + .then(res => res.json()) + .then(res => { + if (res.success) { + this.setState({ displayWav: false }); + this.requestPrompts(this.uuid); + this.requestUserDetails(this.uuid); + this.setState({ + blob: undefined, + audioLen: 0 + }); + } else { + alert("There was an error in saving that audio"); + } + }) + .catch(err => console.log(err)); + }; + silenceDetection = stream => { const options = { interval: "150", From 6e916f09efa5fd79d85efd12239dda8afc965a36 Mon Sep 17 00:00:00 2001 From: Thorsten Mueller Date: Mon, 11 Oct 2021 21:33:58 +0200 Subject: [PATCH 2/5] Adjustments based on PR feedback. --- backend/app/api.py | 2 +- backend/app/db.py | 3 +++ backend/app/file_system.py | 3 ++- frontend/src/App/Record.js | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/app/api.py b/backend/app/api.py index 006da7e..62191e2 100644 --- a/backend/app/api.py +++ b/backend/app/api.py @@ -34,7 +34,7 @@ class AudioAPI: def save_audio(self, audio: bytes, uuid: str, prompt: str): user_audio_dir = AudioFS.get_audio_path(uuid) - if prompt[0:13] == "___SKIPPED___": + if prompt[:13] == "___SKIPPED___": res = DB.skipPhrase(uuid) # Save skipped phrase to textfile diff --git a/backend/app/db.py b/backend/app/db.py index f41f423..9761862 100644 --- a/backend/app/db.py +++ b/backend/app/db.py @@ -126,6 +126,9 @@ def update_user_metrics(uuid: str, time: float, char_len: int) -> response: @staticmethod def skipPhrase(uuid: str) -> response: + '''Increase value of prompted phrase number by one in table usermodel for recording uuid to skip this phrase. + This will not affect average speech speed calculation. + ''' try: query = UserModel \ .update( diff --git a/backend/app/file_system.py b/backend/app/file_system.py index db80ca6..101e87d 100644 --- a/backend/app/file_system.py +++ b/backend/app/file_system.py @@ -69,8 +69,9 @@ def save_meta_data(user_audio_dir, uuid, wav_file_id, prompt): @staticmethod def save_skipped_data(user_audio_dir, uuid, prompt): + '''Save skipped phrase in file -skipped.txt.''' path = os.path.join(user_audio_dir, '%s-skipped.txt' % uuid) - data = "{}\n".format(prompt[13:len(prompt)+13]) + data = "{}\n".format(prompt.lstrip('___SKIPPED___')) with open(path, 'a') as f: f.write(data) diff --git a/frontend/src/App/Record.js b/frontend/src/App/Record.js index 26e3d29..f52fc05 100644 --- a/frontend/src/App/Record.js +++ b/frontend/src/App/Record.js @@ -288,7 +288,7 @@ class Record extends Component { }; skipCurrent = () => { - // prompt_num in DB um 1 erhöhen und Textfile -skipped.txt anlegen und Sätze dort protokollieren + // Send static text '___SKIPPED___' as prefix to original phrase to backend API for being filtered out. postAudio("", "___SKIPPED___" + this.state.prompt, this.uuid) .then(res => res.json()) .then(res => { From 37a38a6f3e1431543db8eabe20e361608318afb4 Mon Sep 17 00:00:00 2001 From: Thorsten Mueller Date: Wed, 13 Oct 2021 18:51:28 +0200 Subject: [PATCH 3/5] Adjusted docstring according to Google styleguide. --- backend/app/db.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/backend/app/db.py b/backend/app/db.py index 9761862..f398ba8 100644 --- a/backend/app/db.py +++ b/backend/app/db.py @@ -126,9 +126,15 @@ def update_user_metrics(uuid: str, time: float, char_len: int) -> response: @staticmethod def skipPhrase(uuid: str) -> response: - '''Increase value of prompted phrase number by one in table usermodel for recording uuid to skip this phrase. - This will not affect average speech speed calculation. - ''' + """Skip phrase when 'S' pressed in frontend app. + + Increase value of prompted phrase number by one in database table 'usermodel' for recording uuid to skip this phrase. + This will not affect average speech speed calculation. + + Args: + uuid (str): UUID of recording session to skip phrase in. + + """ try: query = UserModel \ .update( From 6396c3d944751d2921fa81d7940a94667e846e74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20M=C3=BCller?= Date: Wed, 13 Oct 2021 21:15:34 +0200 Subject: [PATCH 4/5] Fix dosctring typo. --- backend/app/file_system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/file_system.py b/backend/app/file_system.py index 101e87d..1c59d0a 100644 --- a/backend/app/file_system.py +++ b/backend/app/file_system.py @@ -69,7 +69,7 @@ def save_meta_data(user_audio_dir, uuid, wav_file_id, prompt): @staticmethod def save_skipped_data(user_audio_dir, uuid, prompt): - '''Save skipped phrase in file -skipped.txt.''' + """Save skipped phrase in file -skipped.txt.""" path = os.path.join(user_audio_dir, '%s-skipped.txt' % uuid) data = "{}\n".format(prompt.lstrip('___SKIPPED___')) From a5c085b71f11b5b61e6c992bcf624fb1a7d93ad2 Mon Sep 17 00:00:00 2001 From: Kris Gesling Date: Thu, 14 Oct 2021 12:19:51 +0930 Subject: [PATCH 5/5] Reduce line-length of docstring --- backend/app/db.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/app/db.py b/backend/app/db.py index f398ba8..f1ac81d 100644 --- a/backend/app/db.py +++ b/backend/app/db.py @@ -128,7 +128,8 @@ def update_user_metrics(uuid: str, time: float, char_len: int) -> response: def skipPhrase(uuid: str) -> response: """Skip phrase when 'S' pressed in frontend app. - Increase value of prompted phrase number by one in database table 'usermodel' for recording uuid to skip this phrase. + Increase value of prompted phrase number by one in database table + 'usermodel' for recording uuid to skip this phrase. This will not affect average speech speed calculation. Args: