From 165d25a7a7ab59d30aebb117904205355234e8b9 Mon Sep 17 00:00:00 2001 From: Dadangdut33 <57717531+Dadangdut33@users.noreply.github.com> Date: Sun, 26 Nov 2023 01:34:02 +0700 Subject: [PATCH] update packages version and fix bug - add torch and torchaudio version in requirements, remove torchvision - faster whisper now use the v0.10.0 - updated stable-ts, whisper, and webrtcvad version - add pause to downloading faster whisper model - now dialog interaction is disabled disable when downloading model from dialog - fix for #54, the problem was that i forgot that fg was set in the parameter - now enforce ffmpeg instead of asking continue or not when failed to install --- requirements.txt | 14 +- speech_translate/_logging.py | 6 +- speech_translate/ui/custom/dialog.py | 46 ++++ speech_translate/ui/custom/download.py | 57 +++-- speech_translate/ui/frame/setting/general.py | 31 +-- speech_translate/ui/template/detached.py | 2 +- speech_translate/ui/window/main.py | 196 +++++++++--------- speech_translate/utils/audio/file.py | 3 - .../utils/translate/translator.py | 27 ++- speech_translate/utils/whisper/download.py | 2 + 10 files changed, 226 insertions(+), 158 deletions(-) diff --git a/requirements.txt b/requirements.txt index dca29d8..91de679 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ -torch -torchvision -torchaudio +torch==2.1.1 +torchaudio==2.1.1 deep-translator==1.11.1 notify-py==0.3.42 loguru @@ -15,13 +14,10 @@ requests==2.31.0 scipy==1.11.3 sounddevice==0.4.6 soundfile==0.12.1 -webrtcvad==2.0.10 +webrtcvad @ git+https://github.com/wiseman/py-webrtcvad.git@e283ca41df3a84b0e87fb1f5cb9b21580a286b09 darkdetect==0.8.0 -arabic-reshaper==3.0.0 -python-bidi==0.4.2 matplotlib==3.8.0 onnxruntime==1.16.1 demucs==4.0.1 -stable-ts @ git+https://github.com/jianfch/stable-ts.git@b336735ff784bb59690eec8f9f706b0151dda74c -openai-whisper==20231106 -faster-whisper @ git+https://github.com/guillaumekln/faster-whisper.git@1fab6eee59b268f89ff3912a4b19c82751e6bb26 \ No newline at end of file +stable-ts @ git+https://github.com/jianfch/stable-ts.git@71b9f1fcbd1268f8bfe95bba6a394a2bc2e7339b +faster-whisper @ git+https://github.com/SYSTRAN/faster-whisper.git@e1a218fab1ab02d637b79565995bf1a9c4c83a09 \ No newline at end of file diff --git a/speech_translate/_logging.py b/speech_translate/_logging.py index 3a69248..24e905a 100644 --- a/speech_translate/_logging.py +++ b/speech_translate/_logging.py @@ -35,10 +35,10 @@ class StreamStderrToLogger(object): """ def __init__(self, level): self.level = level - # tqdm use stderr to print, so we should consider it as info + # tqdm use stderr to print, so we can consider it as info self.considered_info = [ - "Downloading", "Fetching", "run_threaded", "Estimating duration from bitrate, this may be inaccurate", - "Transcribe", "Translate", "Refine", "Align", "Running", "done", "Using cache found in" + "Downloading", "Fetching", "run_threaded", "Estimating duration from bitrate", "Transcribe", "Translate", + "Translating", "Refine", "Align", "Running", "done", "Using cache found in", "%|#", "0%|" ] def write(self, buf): diff --git a/speech_translate/ui/custom/dialog.py b/speech_translate/ui/custom/dialog.py index eecd138..846fa74 100644 --- a/speech_translate/ui/custom/dialog.py +++ b/speech_translate/ui/custom/dialog.py @@ -81,6 +81,7 @@ def __init__( self.mode = mode self.data_list = [] self.headers = headers + self.interact_disabled = False self.root = Toplevel(self.master) self.root.geometry("+400+250") @@ -201,11 +202,30 @@ def submit(self): self.root.destroy() def on_close(self): + if self.interact_disabled: + return + if not messagebox.askyesno("Cancel", "Are you sure you want to cancel?", parent=self.root): return self.root.destroy() + def disable_interactions(self): + self.interact_disabled = True + self.cb_model.configure(state="disabled") + self.btn_add.configure(state="disabled") + self.btn_delete.configure(state="disabled") + self.btn_start.configure(state="disabled") + self.btn_cancel.configure(state="disabled") + + def enable_interactions(self): + self.interact_disabled = False + self.cb_model.configure(state="readonly") + self.btn_add.configure(state="normal") + self.btn_delete.configure(state="normal") + self.btn_start.configure(state="normal") + self.btn_cancel.configure(state="normal") + class FileImportDialog(FileOperationDialog): def __init__(self, master, title: str, submit_func, theme: str, **kwargs): @@ -375,6 +395,22 @@ def submit(self): if status: # if status is True, meaning process thread is successfully started, then close the window self.root.destroy() + def disable_interactions(self): + super().disable_interactions() + self.cb_engine.configure(state="disabled") + self.cb_source_lang.configure(state="disabled") + self.cb_target_lang.configure(state="disabled") + self.cbtn_transcribe.configure(state="disabled") + self.cbtn_translate.configure(state="disabled") + + def enable_interactions(self): + super().enable_interactions() + self.cb_engine.configure(state="readonly") + self.cb_source_lang.configure(state="readonly") + self.cb_target_lang.configure(state="readonly") + self.cbtn_transcribe.configure(state="normal") + self.cbtn_translate.configure(state="normal") + class TranslateResultDialog(FileOperationDialog): def __init__(self, master, title: str, submit_func, theme: str, **kwargs): @@ -455,6 +491,16 @@ def submit(self): self.submit_func(self.var_engine.get(), self.var_target_lang.get().lower(), [x[0] for x in self.data_list]) self.root.destroy() + def disable_interactions(self): + super().disable_interactions() + self.cb_engine.configure(state="disabled") + self.cb_target_lang.configure(state="disabled") + + def enable_interactions(self): + super().enable_interactions() + self.cb_engine.configure(state="readonly") + self.cb_target_lang.configure(state="readonly") + class RefinementDialog(FileOperationDialog): def __init__(self, master, title: str, submit_func, theme: str, **kwargs): diff --git a/speech_translate/ui/custom/download.py b/speech_translate/ui/custom/download.py index 15651b8..47f818a 100644 --- a/speech_translate/ui/custom/download.py +++ b/speech_translate/ui/custom/download.py @@ -86,7 +86,7 @@ def whisper_download_with_progress_gui( # flag paused = False - def pause_download(): + def toggle_pause(): nonlocal paused paused = not paused if paused: @@ -115,7 +115,7 @@ def pause_download(): lbl_status_text = ttk.Label(status_frame, text=f"Downloading {model_name} model") lbl_status_text.pack(side="left", padx=5, pady=5) - btn_pause = ttk.Button(btn_frame, text="Pause", command=pause_download) + btn_pause = ttk.Button(btn_frame, text="Pause", command=toggle_pause) btn_pause.pack(side="left", fill="x", padx=5, pady=5, expand=True) btn_cancel = ttk.Button(btn_frame, text="Cancel", command=cancel_func, style="Accent.TButton") @@ -305,7 +305,7 @@ def snapshot_download( filtered_repo_files = list( huggingface_hub.utils.filter_repo_objects( - items=[f.rfilename for f in repo_info.siblings], + items=[f.rfilename for f in repo_info.siblings], # type: ignore allow_patterns=allow_patterns, ignore_patterns=ignore_patterns, ) @@ -404,10 +404,6 @@ def faster_whisper_download_with_progress_gui( # clear recent_stderr recent_stderr.clear() - # add label that says downloading please wait - failed = False - msg = "" - f1 = ttk.Frame(root) f1.pack(side="top", fill="x", expand=True) @@ -426,6 +422,9 @@ def faster_whisper_download_with_progress_gui( btn_cancel = ttk.Button(f1, text="Cancel", command=cancel_func, style="Accent.TButton") btn_cancel.pack(side="right", padx=(5, 10), pady=(5, 0)) + btn_pause = ttk.Button(f1, text="Pause", command=lambda: toggle_pause()) + btn_pause.pack(side="right", padx=5, pady=(5, 0)) + # add progress bar that just goes back and forth progress = ttk.Progressbar(f2, orient="horizontal", length=200, mode="indeterminate") progress.pack(expand=True, fill="x", padx=10, pady=(2, 2)) @@ -450,8 +449,14 @@ def update_log(): text_log.insert(1.0, content) text_log.see("end") # scroll to the bottom + failed = False + msg = "" + finished = False + paused = False + killed = False + def run_threaded(): - nonlocal failed, msg + nonlocal failed, msg, finished, paused root.title("Verifying Model") lbl_status_text.configure(text=f"Verifying {model_name} model please wait...") @@ -479,24 +484,52 @@ def run_threaded(): failed = True msg = str(e) + finally: + if not paused: + finished = True + threaded = Thread(target=run_threaded, daemon=True) threaded.start() start_time = time() - while threaded.is_alive(): + def toggle_pause(): + nonlocal paused, killed, threaded + paused = not paused + if paused: + logger.info("Download paused") + btn_pause["text"] = "Resume" + progress.stop() + else: + logger.info("Download resumed") + btn_pause["text"] = "Pause" + progress.start(15) + killed = False + threaded = Thread(target=run_threaded, daemon=True) + threaded.start() + + while not finished: + if paused and not killed: + kill_thread(threaded) + killed = True + recent_stderr.append("Download paused") + update_log() + if bc.cancel_dl: kill_thread(threaded) + finished = True # mark as finished root.destroy() mbox("Download Cancelled", f"Downloading of {model_name} faster whisper model has been cancelled", 0, master) break # check if 2 second have passed. Means probably downloading from the hub if time() - start_time > 2: - root.title("Downloading Faster Whisper Model") + root.title(f"{'Downloading' if not paused else 'Paused downloading of'} Faster Whisper Model") lbl_status_text.configure( - text=f"Downloading {model_name} model, {get_file_amount(storage_folder + '/' + 'blobs')} files downloaded..." + text= + f"{'Downloading' if not paused else 'Paused downloading'} {model_name} model, {get_file_amount(storage_folder + '/' + 'blobs')} files downloaded..." ) - update_log() + if not paused: + update_log() sleep(1) # if cancel button is pressed, return diff --git a/speech_translate/ui/frame/setting/general.py b/speech_translate/ui/frame/setting/general.py index 9d6438e..06ced94 100644 --- a/speech_translate/ui/frame/setting/general.py +++ b/speech_translate/ui/frame/setting/general.py @@ -187,22 +187,6 @@ def __init__(self, root: Toplevel, master_frame: Union[ttk.Frame, Frame]): ) self.btn_log_config.pack(side="left", padx=5, pady=5) - # self.lbl_ignore_stdout = ttk.Label(self.f_logging_2, text="Ignore stdout", width=16) - # self.lbl_ignore_stdout.pack(side="left", padx=5) - # tk_tooltip(self.lbl_ignore_stdout, "Collection to ignore stdout / print from the console.") - # self.entry_ignore_stdout = ttk.Entry(self.f_logging_2) - # self.entry_ignore_stdout.pack(side="left", padx=5, fill="x", expand=True) - # self.entry_ignore_stdout.insert(0, ', '.join(sj.cache["ignore_stdout"])) - # self.entry_ignore_stdout.bind("", lambda e: self.save_ignore_stdout()) - # self.entry_ignore_stdout.bind("", lambda e: self.save_ignore_stdout()) - # tk_tooltip( - # self.entry_ignore_stdout, - # "Collection to ignore stdout / print from the console with its input separated by comma.\n\n" - # "This is useful if you want to ignore some of the stdout / print from the console.\n\n" - # "Example: `Predicting silences(s) with VAD..., Predicted silences(s) with VAD`", - # wrapLength=500, - # ) - self.menu_config_log = Menu(self.master, tearoff=0) self.menu_config_log.add_command( label="Open", image=self.open_emoji, compound="left", command=lambda: start_file(dir_log) @@ -274,7 +258,7 @@ def __init__(self, root: Toplevel, master_frame: Union[ttk.Frame, Frame]): tk_tooltip( self.cbtn_debug_realtime_record, "Show some debugging process of the realtime record.\n\n" - "Enabling will probably slow down the app.", + "Enabling could slow down the app.", ) self.cbtn_debug_recorded_audio = CustomCheckButton( @@ -550,7 +534,7 @@ def failed_func(): kwargs = { "after_func": after_func, "use_faster_whisper": use_faster_whisper, - "cancel_func": lambda: self.cancel_model_download(model, btn), + "cancel_func": lambda: self.cancel_model_download(model, btn, use_faster_whisper), "failed_func": failed_func, } @@ -580,7 +564,7 @@ def failed_func(): ) mbox("Download error", f"Err details: {e}", 0, self.root) - def cancel_model_download(self, model: str, btn: ttk.Button) -> None: + def cancel_model_download(self, model: str, btn: ttk.Button, use_faster_whisper) -> None: """ Cancel whisper model download. @@ -589,7 +573,7 @@ def cancel_model_download(self, model: str, btn: ttk.Button) -> None: if not mbox("Cancel confirmation", "Are you sure you want to cancel downloading?", 3, self.root): return - btn.configure(text="Download", command=lambda: self.model_download(model, btn, False), state="normal") + btn.configure(text="Download", command=lambda: self.model_download(model, btn, use_faster_whisper), state="normal") bc.cancel_dl = True # Raise flag to stop def model_btn_checker(self, model: str, btn: ttk.Button, faster_whisper: bool = False, on_start=False) -> None: @@ -901,10 +885,3 @@ def path_default(self, key: str, element: ttk.Entry, default_path: str, save=Tru element.configure(state="readonly") if save: sj.save_key(key, "auto") - - # def save_ignore_stdout(self): - # _input = self.entry_ignore_stdout.get().split(",") - # _input = [i.strip() for i in _input if i.strip() != ""] # remove any empty string or space - - # sj.save_key("ignore_stdout", _input) - # update_stdout_ignore_list(_input) diff --git a/speech_translate/ui/template/detached.py b/speech_translate/ui/template/detached.py index 8536858..55668fa 100644 --- a/speech_translate/ui/template/detached.py +++ b/speech_translate/ui/template/detached.py @@ -59,7 +59,7 @@ def __init__(self, master: Tk, title: str, winType: Literal["tc", "tl"]): wrapLength=250, ) - self.menuDropdown = Menu(self.root, tearoff=0, fg="white") + self.menuDropdown = Menu(self.root, tearoff=0) self.menuDropdown.add_command(label=self.title, command=self.open_menu, image=self.title_emoji, compound="left") self.menuDropdown.add_command(label="Help", command=self.show_help, image=self.help_emoji, compound="left") self.menuDropdown.add_command( diff --git a/speech_translate/ui/window/main.py b/speech_translate/ui/window/main.py index 3865493..275d7a7 100644 --- a/speech_translate/ui/window/main.py +++ b/speech_translate/ui/window/main.py @@ -713,31 +713,24 @@ def first_open(): self.root.after(2000, self.check_ffmpeg, bc.has_ffmpeg) def check_ffmpeg(self, has_ffmpeg: bool): - ffmpeg_installed = False - user_cancel = False - if not has_ffmpeg: - # prompt to install ffmpeg - if mbox( - "FFmpeg is not found in your system path!", - "FFmpeg is essential for the app to work properly.\n\nDo you want to install it now?", - 3, - ): - success, msg = install_ffmpeg() - if not success: - mbox("Error", msg, 2) + if has_ffmpeg: + return True + + # prompt to install ffmpeg + if mbox( + "FFmpeg is not found in your system path!", + "FFmpeg is essential for the app to work properly.\n\nDo you want to install it now?", + 3, + ): + success, msg = install_ffmpeg() + if not success: + mbox("Error", msg, 2) - if check_ffmpeg_in_path()[0]: - bc.has_ffmpeg = True - ffmpeg_installed = success - else: - ffmpeg_installed = False - else: - ffmpeg_installed = False - user_cancel = True - else: - ffmpeg_installed = True + elif check_ffmpeg_in_path()[0]: + bc.has_ffmpeg = True + return True - return ffmpeg_installed, user_cancel + return False # mic def cb_input_device_init(self): @@ -1306,9 +1299,12 @@ def destroy_transient_toplevel(self, name, similar=False): child.destroy() break - def check_model(self, key, is_english, taskname, task): + def check_model(self, key, is_english, taskname, task, **kwargs): model_name = append_dot_en(key, is_english) try: + if kwargs.get("disabler", None): + kwargs["disabler"]() + # check model first use_faster_whisper = sj.cache["use_faster_whisper"] @@ -1370,6 +1366,9 @@ def check_model(self, key, is_english, taskname, task): self.errorNotif(str(e), use_mbox=True) return False, "" + finally: + if kwargs.get("enabler", None): + kwargs["enabler"]() # ------------------ Rec ------------------ def rec(self): @@ -1395,13 +1394,13 @@ def rec(self): return # Checking args - tc, tl, m_key, engine, source, target, mic, speaker = self.get_args() + tc, tl, m_key, tl_engine, source, target, mic, speaker = self.get_args() if source == target and tl: mbox("Invalid options!", "Source and target language cannot be the same", 2) return # check model first - tl_whisper = engine in model_keys + tl_whisper = tl_engine in model_keys model_tc = None if tc: # check tc model if tc status, model_tc = self.check_model(m_key, source == "english", "mic record", self.rec) @@ -1410,18 +1409,18 @@ def rec(self): if tl and tl_whisper: # if tl and using whisper engine, check model - status, engine = self.check_model(engine, source == "english", "recording", self.rec) + status, tl_engine = self.check_model(tl_engine, source == "english", "recording", self.rec) if not status: return # if only tl and using whisper, replace model_tc with engine if tl and not tc and tl_whisper: - model_tc = engine + model_tc = tl_engine assert model_tc is not None, "model_tc is not set, this should not happened. Report this as a bug at https://github.com/Dadangdut33/Speech-Translate/issues" # check when using libre - if engine == "LibreTranslate": + if tl and tl_engine == "LibreTranslate": # check wether libre_host is set or not if sj.cache["libre_host"].strip() == "": mbox( @@ -1442,24 +1441,13 @@ def rec(self): return False # check ffmpeg - success, user_cancel = self.check_ffmpeg(check_ffmpeg_in_path()[0]) - if not success: - # ask if user want to continue processing - if not mbox( - "FFMpeg is not installed!", - "The program needs ffmpeg to process files and will probably not work without it. Do you still want to continue regardless of it?", - 3, self.root - ): - return - - if user_cancel: + if not self.check_ffmpeg(check_ffmpeg_in_path()[0]): mbox( - "Cancelled", - "The program needs ffmpeg to process files and will probably not work without it. Please install it first.", - 2, + "FFmpeg is not installed!", + "The program needs ffmpeg to process files and will probably not work without it. Please install and add it to PATH first.", + 3, self.root ) - - return + return False # ui changes self.tb_clear() @@ -1474,7 +1462,7 @@ def rec(self): device = mic if not is_speaker else speaker recThread = Thread( target=record_session, - args=(source, target, engine, model_tc, device, tc, tl, is_speaker), + args=(source, target, tl_engine, model_tc, device, tc, tl, is_speaker), daemon=True, ) recThread.start() @@ -1509,8 +1497,11 @@ def import_file(self): ) return - def do_process(m_key, engine, source, target, tc, tl, files): - tl_whisper = engine in model_keys + def do_process(m_key, tl_engine, source, target, tc, tl, files): + nonlocal prompt + m_check_kwargs = {"disabler": prompt.disable_interactions, "enabler": prompt.enable_interactions} + + tl_whisper = tl_engine in model_keys # lang is lowered when send from FileImportDialog if source == target and tl: mbox("Invalid options!", "Source and target language cannot be the same", 2) @@ -1519,23 +1510,26 @@ def do_process(m_key, engine, source, target, tc, tl, files): # check model first model_tc = None if tc: # check tc model if tc - status, model_tc = self.check_model(m_key, source == "english", "file import", self.import_file) + status, model_tc = self.check_model(m_key, source == "english", "file import", do_process, **m_check_kwargs) if not status: return False if tl and tl_whisper: # if tl and using whisper engine, check model - status, engine = self.check_model(engine, source == "english", "file import", self.import_file) + status, tl_engine = self.check_model( + tl_engine, source == "english", "file import", do_process, **m_check_kwargs + ) if not status: return False # if only tl and using whisper, replace model_tc with engine if tl and not tc and tl_whisper: - model_tc = engine + model_tc = tl_engine assert model_tc is not None, "model_tc is not set, this should not happened. Report this as a bug at https://github.com/Dadangdut33/Speech-Translate/issues" - if engine == "LibreTranslate": + # check when using libre + if tl and tl_engine == "LibreTranslate": # check wether libre_host is set or not if sj.cache["libre_host"].strip() == "": mbox( @@ -1556,24 +1550,15 @@ def do_process(m_key, engine, source, target, tc, tl, files): return False # check ffmpeg - success, user_cancel = self.check_ffmpeg(check_ffmpeg_in_path()[0]) - if not success: - # ask if user want to continue processing - if not mbox( - "FFMpeg is not installed!", - "The program needs ffmpeg to process files and will probably not work without it. Do you still want to continue regardless of it?", - 3, self.root - ): - return False - - if user_cancel: + prompt.disable_interactions() + if not self.check_ffmpeg(check_ffmpeg_in_path()[0]): mbox( - "Cancelled", - "The program needs ffmpeg to process files and will probably not work without it. Please install it first.", - 2, + "FFmpeg is not installed!", + "The program needs ffmpeg to process files and will probably not work without it. Please install and add it to PATH first.", + 3, self.root ) - return False + prompt.enable_interactions() # ui changes self.tb_clear() @@ -1586,7 +1571,7 @@ def do_process(m_key, engine, source, target, tc, tl, files): # Start thread try: recFileThread = Thread( - target=process_file, args=(list(files), model_tc, source, target, tc, tl, engine), daemon=True + target=process_file, args=(list(files), model_tc, source, target, tc, tl, tl_engine), daemon=True ) recFileThread.start() @@ -1652,31 +1637,24 @@ def refine_file(self): return def do_process(m_key, files): + nonlocal prompt # file = (source_file, mod_file) # check model first - status, model_tc = self.check_model(m_key, False, "file refinement", self.refine_file) + m_check_kwargs = {"disabler": prompt.disable_interactions, "enabler": prompt.enable_interactions} + status, model_tc = self.check_model(m_key, False, "file refinement", do_process, **m_check_kwargs) if not status: return False # check ffmpeg - success, user_cancel = self.check_ffmpeg(check_ffmpeg_in_path()[0]) - if not success: - # ask if user want to continue processing - if not mbox( - "FFMpeg is not installed!", - "The program needs ffmpeg to process files and will probably not work without it. Do you still want to continue regardless of it?", - 3, self.root - ): - return False - - if user_cancel: + prompt.disable_interactions() + if not self.check_ffmpeg(check_ffmpeg_in_path()[0]): mbox( - "Cancelled", - "The program needs ffmpeg to process files and will probably not work without it. Please install it first.", - 2, + "FFmpeg is not installed!", + "The program needs ffmpeg to process files and will probably not work without it. Please install and add it to PATH first.", + 3, self.root ) - return False + prompt.enable_interactions() # ui changes self.tb_clear() @@ -1739,6 +1717,7 @@ def align_file(self): return def do_process(m_key, files): + nonlocal prompt # file = (source_file, mod_file, lang) # filter lang to check all english or not all_english = True @@ -1748,29 +1727,21 @@ def do_process(m_key, files): break # load .en model if all language is english - status, model_tc = self.check_model(m_key, all_english, "file alignment", self.align_file) + m_check_kwargs = {"disabler": prompt.disable_interactions, "enabler": prompt.enable_interactions} + status, model_tc = self.check_model(m_key, all_english, "file alignment", do_process, **m_check_kwargs) if not status: return False # check ffmpeg - success, user_cancel = self.check_ffmpeg(check_ffmpeg_in_path()[0]) - if not success: - # ask if user want to continue processing - if not mbox( - "FFMpeg is not installed!", - "The program needs ffmpeg to process files and will probably not work without it. Do you still want to continue regardless of it?", - 3, self.root - ): - return False - - if user_cancel: + prompt.disable_interactions() + if not self.check_ffmpeg(check_ffmpeg_in_path()[0]): mbox( - "Cancelled", - "The program needs ffmpeg to process files and will probably not work without it. Please install it first.", - 2, + "FFmpeg is not installed!", + "The program needs ffmpeg to process files and will probably not work without it. Please install and add it to PATH first.", + 3, self.root ) - return False + prompt.enable_interactions() # ui changes self.tb_clear() @@ -1832,7 +1803,7 @@ def translate_file(self): ) return - def do_process(engine, lang_target, files): + def do_process(tl_engine, lang_target, files): # lang is lowered when send from TranslateResultDialog # no check because not using any model and no need for ffmpeg # ui changes @@ -1842,9 +1813,30 @@ def do_process(engine, lang_target, files): bc.enable_file_process() + # check when using libre + if tl_engine == "LibreTranslate": + # check wether libre_host is set or not + if sj.cache["libre_host"].strip() == "": + mbox( + "LibreTranslate host is not set!", + "LibreTranslate host is not set! Please set it first in the settings!", + 2, + ) + return False + + # check api key + if not sj.cache["supress_libre_api_key_warning"] and sj.cache["libre_api_key"].strip() == "": + if not mbox( + "LibreTranslate API key is not set!", + "WARNING!! LibreTranslate API key is not set! Do you want to continue anyway?", + 3, + self.root, + ): + return False + # Start thread try: - translateThread = Thread(target=translate_result, args=(files, engine, lang_target), daemon=True) + translateThread = Thread(target=translate_result, args=(files, tl_engine, lang_target), daemon=True) translateThread.start() return True diff --git a/speech_translate/utils/audio/file.py b/speech_translate/utils/audio/file.py index cca1e0a..1bece4b 100644 --- a/speech_translate/utils/audio/file.py +++ b/speech_translate/utils/audio/file.py @@ -1,5 +1,4 @@ import sys -import gc from os import path from datetime import datetime from threading import Thread @@ -748,7 +747,6 @@ def update_modal_ui(): logger.warning("Failed to destroy progress window") finally: cuda.empty_cache() - gc.collect() bc.mw.from_file_stop(prompt=False, notify=False) # reset processed list processed_tc = [] @@ -1039,7 +1037,6 @@ def run_mod(): logger.warning("Failed to destroy progress window") finally: cuda.empty_cache() - gc.collect() if mode == "refinement": bc.mw.refinement_stop(prompt=False, notify=False) else: diff --git a/speech_translate/utils/translate/translator.py b/speech_translate/utils/translate/translator.py index 387f001..ecb020d 100644 --- a/speech_translate/utils/translate/translator.py +++ b/speech_translate/utils/translate/translator.py @@ -3,11 +3,34 @@ from ..helper import get_similar_keys, no_connection_notify from .language import GOOGLE_KEY_VAL, LIBRE_KEY_VAL, MYMEMORY_KEY_VAL +from tqdm.auto import tqdm import requests + +def tl_batch_with_tqdm(self, batch: List[str], **kwargs) -> list: + """Translate a batch of texts + + Args: + batch (list): List of text to translate + + Returns: + list: List of translated text + """ + if not batch: + raise Exception("Enter your text list that you want to translate") + arr = [] + for text in tqdm(batch, desc="Translating"): + translated = self.translate(text, **kwargs) + arr.append(translated) + + return arr + + # Import the translator try: from deep_translator import GoogleTranslator, MyMemoryTranslator + GoogleTranslator._translate_batch = tl_batch_with_tqdm + MyMemoryTranslator._translate_batch = tl_batch_with_tqdm except Exception as e: GoogleTranslator = None MyMemoryTranslator = None @@ -80,6 +103,7 @@ def google_tl(text: List[str], from_lang: str, to_lang: str, proxies: Dict, debu from deep_translator import GoogleTranslator TlCon.GoogleTranslator = GoogleTranslator + TlCon.GoogleTranslator._translate_batch = tl_batch_with_tqdm except Exception: no_connection_notify() return is_Success, "Error: Not connected to internet" @@ -142,6 +166,7 @@ def memory_tl(text: List[str], from_lang: str, to_lang: str, proxies: Dict, debu from deep_translator import MyMemoryTranslator TlCon.MyMemoryTranslator = MyMemoryTranslator + TlCon.MyMemoryTranslator._translate_batch = tl_batch_with_tqdm except Exception: no_connection_notify() return is_Success, "Error: Not connected to internet" @@ -224,7 +249,7 @@ def libre_tl( req["api_key"] = libre_api_key arr = [] - for q in text: + for q in tqdm(text, desc="Translating"): req["q"] = q response = requests.post(adr, json=req, proxies=proxies).json() if "error" in response: diff --git a/speech_translate/utils/whisper/download.py b/speech_translate/utils/whisper/download.py index 03457b4..1b36f33 100644 --- a/speech_translate/utils/whisper/download.py +++ b/speech_translate/utils/whisper/download.py @@ -5,6 +5,7 @@ from faster_whisper.utils import _MODELS as FW_MODELS from huggingface_hub import HfApi from huggingface_hub.file_download import repo_folder_name +from loguru import logger from speech_translate.ui.custom.download import whisper_download_with_progress_gui, faster_whisper_download_with_progress_gui @@ -116,6 +117,7 @@ def verify_model_faster_whisper(model_key: str, cache_dir) -> bool: for _root, _dirs, files in os.walk(blob_folder): for file in files: if file.endswith(".incomplete") or file.endswith(".lock"): + logger.warning("Found incomplete file in blob folder, meaning that the download is not finished") return False # should be safe to assume that model is downloaded