From e471d3e1f8d0c92b192f5f48427713cc83a7fafd Mon Sep 17 00:00:00 2001 From: David Kifer Date: Mon, 12 Jan 2026 15:15:37 -0500 Subject: [PATCH] syncing latest revisions - dk123 --- .../__pycache__/extractor.cpython-313.pyc | Bin 6471 -> 6844 bytes .../__pycache__/main.cpython-313.pyc | Bin 18409 -> 18685 bytes .../__pycache__/tracker.cpython-313.pyc | Bin 4827 -> 5217 bytes .../__pycache__/transcriber.cpython-313.pyc | Bin 0 -> 9977 bytes .../__pycache__/translator.cpython-313.pyc | Bin 12775 -> 12671 bytes .../__pycache__/utils.cpython-313.pyc | Bin 12686 -> 12612 bytes .../ai_transcriber_v2/extractor.py | 34 ++++---- video_transcription/ai_transcriber_v2/main.py | 51 ++++++------ .../ai_transcriber_v2/tracker.py | 19 +++-- .../ai_transcriber_v2/transcriber.py | 73 +++++++++--------- .../ai_transcriber_v2/translator.py | 12 +-- 11 files changed, 100 insertions(+), 89 deletions(-) create mode 100644 video_transcription/ai_transcriber_v2/__pycache__/transcriber.cpython-313.pyc diff --git a/video_transcription/ai_transcriber_v2/__pycache__/extractor.cpython-313.pyc b/video_transcription/ai_transcriber_v2/__pycache__/extractor.cpython-313.pyc index ff2d352fe275f428efda02311dbe2f896fbc828f..379860648d6c9845706d4d3d066a8550073c85dd 100644 GIT binary patch delta 1803 zcmZuxO-vg{6rQoy_Tu&0vDbeX8*D`RH3@$ve<=L41r&lyuuzfGf(+hL^XGJSoko>H zl~a{N6_J+%Ike~WP}LF_)K+Q2C5I}KkyZj3s?aK@N@=U4IrY++4XfbRPukfxZ{B?G z&HH=Y^G_bHjjoH;czV65xf73ZgiE26Y0PrbN~}?oGKUbcr8v6sDO<`C zLW`JGQO>G!_Vw#$@m1*Hl6UZ`JC4w*`HF+VGMaS4ASc0w=!G@h5b?a0B4k79dW52= zlIG?E%wuea$EGs@n@ZC2OEM{0mvajX^ly;~$q}%aWqUOR$>f{<=o}N zJA8O!?SA@xsu=0i_^tz&_n!kH{1TZgz61W4QZb@xd>;NV2c(4gQCIsZNRWv=3$i+UEt`>Z zvza_etJ&NtX`~0$ux{NpO_<p@n-4c;1PaQW)hXpMKxAAg)G?`|DfT*@CW9bW{bmi*4e`LMs$q{vSjiA- z1re5IBEh&l=yp@K#AR1M$`O_pQV&b^M7x)=3P+bW!4c)_ET!sfI-kkrNH0A+$+RR4 zPwbgdi@_y_7iOHE zBVhk=>jpw91~(mT)DJH_a5}IHes)Go0~Ne|?ySQh5M41Gfm5#7kxslK=37SoX{#BA z(4>C5H)04`@_iOHZNS zn}tK~V$X^H7W4_G$m&^d{*sM$vy%Nx)?1jIV)72i`Ft&`&e;f9$z78P9cHLxPR}VV z0_kQvuMl_-x(_Fhn~Wf!uUg}7<^abhT*Ay!|lC2b8BW-jO~cAV*Q9F zj>1}?wOpFfL>aydG?hsk=9x4YY%iCNYvOyb77Tq})@S_>g{>RK@VLe&_gvDm@)>(t z`b2`Y-;KwLJ!e5NJpVV zmIkcE_pRhI`DOV6nV?#1R4OdRf0;4H`>1Lkx%ZKM9|`-&`3q`#!MU*SMZJWjzguJ2 N`)U}EVeHfK{sq!(fLH(k delta 1789 zcmah}O>7%Q6rS;V?Ty#7YkTd)No%rkXc8xJn%GI3xM|a*rD|IG18$&IR7H-xO*cyH zc6L)x3TlrCA<=386)uH&UeecbDGw^K!JwnI>s0{iv{hjNm5uUu>-Vt*gbspg{uYxq!1h6aZq^mpaPV-G* z7Gi;Fu8LN7{pyfIg~W32B6pn)M1XmB7=S!CiOAx6o5&*_k;&*Q&e{y?YM%Sbp7jI-ODQXL?8*=dP4RQM;;NU|W0dwVJD;1H&KMdFGSh`MV`0uTcxtFja6P%_3iCUt9VTA)ZO0n>*E_rq&_5wR3C$3Z z7wU$ZWlE^X1UCRTwT>#1=>mYfCv0!aiFA{{ih^{YM%3UWdWtIKS0N+@YWAx^^1v4) zLC^QJ-T>fjUktlg32_V2#ep~rU^wZr`4dzrBkfHSXR_v0 zW+A5+a6iT3jP(SN@5EdivV2`jN0;_m(vU5r*5oEjXu9jHv%Jw_s@T1hwLA&inIyXR zxJ0Qh7AK3xEGc0NN%DiY+tJ3;vK%Hap>dujH0dTc(EvFsM4WUIMBk_b(Up~k&f5A|H`Co!kK27_B=OJ z5A*jvm#}k7*xFguq>nvIy0^xngZM0^z6pl}l8%~B1v7~)-sBeC5$j+6Ezk>LI|&54 zT%GhJ+(8ZmZ;G@*09WU>F7!(`qSJT+>oa;jGnZ0zKnHY@>q(qj5vl&w}R1+`cnU+&8={c>S8Yb2<^F8Y5bOD=sex`@K zQa`%`{r8s8OAE^G8O=2GMGdn%jeE$w`cRD3g5CZ3!X*v2FoVlX8!-|0FzHb1T9ri_JYQ#a={10SX6N%|RYIRLl{9(%~Ds1U0m=%z2$ zs4a|ia81tF^zBwxUBTeoNV7qv6fn!zIp&_LoL2WtWY1Q_NBh+h}|P$?uk9jIB zxq{hyhj-GY?3^_U`7*y?>T?F>7|fcn*&OynRVw-gs6@b(nhV48h1|lNwhy16e)iZJ uY~=295W;m(w+{U4z_Sj-pF#UWrwl_6qY6|WcecRblSA+%gdyx?>HGs60h40@ diff --git a/video_transcription/ai_transcriber_v2/__pycache__/main.cpython-313.pyc b/video_transcription/ai_transcriber_v2/__pycache__/main.cpython-313.pyc index d2d6ac2c8194a962ff8f5446d3ce4df5a6db1cd5..507880a90ed4c7a95904a39a68df75410dce1a90 100644 GIT binary patch delta 1756 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 diff --git a/video_transcription/ai_transcriber_v2/__pycache__/tracker.cpython-313.pyc b/video_transcription/ai_transcriber_v2/__pycache__/tracker.cpython-313.pyc index 9aaa6cfe172f3b90d9cbb6e93d6e28ace72f3163..600bb3145328b87fe37c6a51201124cdebc75c1c 100644 GIT binary patch delta 1430 zcmZ`(OKclO7@oDgUcYwzs_RG6)OKrUoun?*Bx*!rlC*UaDRG2XRe7vrZOO(s+IY*X zLxnil0wGaxXre(%kSZPrB(5kIIKmmB<{@k?9Ow})l*f?+|E%KxC0N>T_WNJoKmW}7 z`^+Oz_?_oH2!7wpsr4D(wh*&5?VpP!CLsC78R|d?CuCHa*xourK4d&jJSY!Vo+Y2K zVSl0@kwjpdrZzjO6v-o3m_N=1530;;Z=GXPa_W?{)JfX)|D=^b(gEp3OKeb1UA9U5 zq|GY10KTl8={JD0GM`4{y?zlMmIOH{Ajw~_W0459+>KlerI8d$ASo;lkK22JctmEw zdPWunRIr`Y8kL7DFC3Tp$5MHj_E8w^$3Y)L8p)$lWRk&o>1+bw%Thv$CeS*ApORw0 zpO)f)SIF14?_4&M)zsHjjeKUWGa?B&K4k{T7mi_11T-)Ok^JO1@61?qPhdHQ$&<6r zslp|&E;ysXY1B8)cV)uMpm+Fd3rz{%l#QuK!h~TWKmy z5Pee5bQ?|ePPL(IsFw8UnxJNSduLLm@%VYLyafX;(DO+P1anoV_PILS4-Izenw-qh3?$nz~9SZs3~`rNCp{0%)TjgvfjK_I%eH zx<7qy`T_aYf0HSYi-9j&?vjo-VAm=(c}=fX*G{On1mzZ##;OKB-x`qWt9=HO`a91B zY>D1z)3I1Ct(d&j#HzBw^jZy0 zm0n`g3EcoO9dnAIn%wodYH4xlhV^~G{hJJ?r>yHk?-r&fZH?R7_Y?QqbWLsOtDBly z#CIW%{vR1TWGC2aJ$9mCtP@Bb1X2&v%ZGt-n+H=M+VQ6k{OOOc9{R`HzAo~0P<$W7 zcP||w(PEK(6xpinXxrKmx&RrWcqf=W2xbq1Vq54Up@RnY(ZKHV5gM^rbRR``xsUuG r_@Tm&i0h#60Sb2`p5Xnldt+T8v0Hw~kN(Em8QWtQSqZ)CpdaU7=sQx} delta 1177 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 literal 0 HcmV?d00001 diff --git a/video_transcription/ai_transcriber_v2/__pycache__/translator.cpython-313.pyc b/video_transcription/ai_transcriber_v2/__pycache__/translator.cpython-313.pyc index 190b8639b6dba84949988ee62384ae8c8d652c09..7930d8867e89b2556cba308af1dbfa4924dcf559 100644 GIT binary patch delta 726 zcmcIiO=uHA6n<}JH@n&2CfS%8t4Xj4gp#B-7KzwHNg7b7Ak(!~@L*~aiV&nC)MJlY zMC5@NZ{DmYS&E0AG#&~nl-jE|LGUI$7*MFQ0c*jtZ#w&Y{aaBa<7F*9~=i>l38Nlo%0HOQnfQb4L2dYX}69zfFo;H0=SY=j0Vb@sK z@D1Upl1#WNt+6bv^9E0eVcO++9HKryjWHTg#rmfj80EhUS6id=CrBpiZThbc)%k}3>M>2+WZEV97&p;cCX}YRD z$7ax1x0tfD=e6mzzJZ;f6+MN9CY^9O_sjIqxUGmtO`#vg1Jr2EtfEevW}Zi7|DVle zZVHPoS~Dfv*Z&cBy85)dVz$^6YMZS!25D6=O{=A}UZxSjgQRH^Lfg>Bh_&cJ zPf897Po&_@o7#&ko&-@ND2PzB2M-=Bh@u|#V4$0yzl4ar=0Q4 zFjNrh`JsGi_P#MenZ#wBqP3`JAOw)50OO+oT*(jR zuJ_Zjno+qSi)7rC@e;MM#)jAq-i)tVjQH^f+f4%4CUq;pMj9T%<5F`toKTXa(E)%B z+-huGkorgy-j(7p&z3JLyk$M5kADF8gTIJk7H&xKcqF5X*68;4MUk-)S0DvA%%V^r zT|4oFeA``@A5v**)ym_F>EK821yXQxzFh=+B0kcCHFcWyGt36A5)Xb2B#461V2pVM z_4itdsa(S`eK@XXyxZy;WpBz`H2CKES6vey=?{E&XeA)nR)X$jBTUFT-ZYbJ)jB5H zI7dcs#Lov=x(}ZEf(_fcH*M3pW(i!k)wCnm_cXlqIB8&K6Zfe@VOBqA4w>wkDGQvV z*dDR|nZ&;TB9Ya^yzsH!<{k}22%ZkVBpcXm9S|JG1cwCPvWCgHyJkJ{|NcsMx#I;% z^a7j}YMQ$zRH6*r5ZdwsoYFQYFO1NZDn#K+u&oi|#m@Go9)Odt_R}-eh7Qn#NQ!Eg z=DMAeO20@4i>hs>s@44LT-9E*?LxLRlb>?ziOTs>xoDU33srG9Gc%dZO*@WLxh6uo zJlN{Qz19+QmwVrkUqXeq AYybcN diff --git a/video_transcription/ai_transcriber_v2/__pycache__/utils.cpython-313.pyc b/video_transcription/ai_transcriber_v2/__pycache__/utils.cpython-313.pyc index 8750af8bdff95000ec22c11ee223c26d7b92ae03..cbb9d34176af8262f4305067e9bd0a7995b4f64f 100644 GIT binary patch delta 14 VcmeB6K9aN{otaT;^Cspyx&SS%1-<|P delta 88 zcmWm4!3}^Q3;@6f^O!E-&mjoXMo6F~1v`ebn7D#tIE?zfyVoP0n_CbpC?u%_7%U^q m68B0xI#`c_1dX%{hvJcpinJf$n 1.0: - print(f"❌ CRITICAL: Duration mismatch detected!") - print(f" Original: {original_duration:.2f}s") - print(f" New: {new_duration:.2f}s") - print(" This indicates truncated video stream. Aborting.") + tracker.logger.error(f"❌ CRITICAL: Duration mismatch detected!") os.remove(output_path) raise Exception("Embedding failed: Duration mismatch > 1s.") - print(f"Subtitles embedded successfully: {output_path}") + tracker.logger.info(f"Subtitles embedded successfully: {output_path}") return True else: - print("Error: Embedding failed.") + tracker.logger.error("Error: Embedding failed.") return False diff --git a/video_transcription/ai_transcriber_v2/main.py b/video_transcription/ai_transcriber_v2/main.py index 77f647d..f5f6f43 100644 --- a/video_transcription/ai_transcriber_v2/main.py +++ b/video_transcription/ai_transcriber_v2/main.py @@ -27,6 +27,8 @@ from diarizer import diarize_audio, merge_diarization_with_transcript import tracker from tracker import JobStatus +from tqdm import tqdm + def save_srt_with_speakers(segments, output_path): """Helper to save SRT with speaker labels prepended to text.""" def format_timestamp(seconds: float): @@ -50,7 +52,7 @@ def save_srt_with_speakers(segments, output_path): f.write(f"{i}\n") f.write(f"{start} --> {end}\n") f.write(f"{text}\n\n") - print(f"SRT saved to: {output_path}") + tracker.logger.info(f"SRT saved to: {output_path}") def process_file(file_path, args, source_lang=None, loaded_model=None, service_status=None): tracker.logger.info(f"=== Processing: {file_path} ===") @@ -324,34 +326,35 @@ def main(): loaded_model = load_whisper_model(args.model) # ----------------------- - # Initialize Graceful Exit Handler - killer = GracefulKiller() - + # --- Collect All Files --- + all_files = [] video_extensions = ('.mp4', '.mkv', '.mov', '.avi', '.webm', '.flv', '.wmv', '.m4v') for input_path in valid_inputs: + if os.path.isfile(input_path): + all_files.append(input_path) + elif os.path.isdir(input_path): + for root, dirs, files in os.walk(input_path): + for file in files: + if file.lower().endswith(video_extensions): + all_files.append(os.path.join(root, file)) + + if not all_files: + print("No video files found to process.") + return + + # --- Batch Process with Progress Bar --- + pbar = tqdm(all_files, desc="Batch Progress", unit="file", dynamic_ncols=True, leave=True) + + for file_path in pbar: if killer.kill_now: break - - if os.path.isfile(input_path): - process_file(input_path, args, source_lang, loaded_model=loaded_model, service_status=service_status) - elif os.path.isdir(input_path): - found = False - for root, dirs, files in os.walk(input_path): - if killer.kill_now: - break - - for file in files: - if killer.kill_now: - break - - if file.lower().endswith(video_extensions): - found = True - process_file(os.path.join(root, file), args, source_lang, loaded_model=loaded_model, service_status=service_status) - if not found: - print(f"No video files found in {input_path}") - else: - print(f"Error: Invalid input path '{input_path}'") + + # Update progress bar description with current file + filename = os.path.basename(file_path) + pbar.set_description(f"File: {filename[:30]}") + + process_file(file_path, args, source_lang, loaded_model=loaded_model, service_status=service_status) if killer.kill_now: print("\n🛑 Process stopped by user. Progress saved in database.") diff --git a/video_transcription/ai_transcriber_v2/tracker.py b/video_transcription/ai_transcriber_v2/tracker.py index a24aa8d..26b196e 100644 --- a/video_transcription/ai_transcriber_v2/tracker.py +++ b/video_transcription/ai_transcriber_v2/tracker.py @@ -14,13 +14,22 @@ log_dir = "logs" os.makedirs(log_dir, exist_ok=True) log_file = os.path.join(log_dir, f"transcriber_{HOSTNAME}_{datetime.now().strftime('%Y%m%d')}.log") +# Create formatters +log_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + +# File Handler (Full Detail) +file_handler = logging.FileHandler(log_file) +file_handler.setFormatter(log_formatter) +file_handler.setLevel(logging.INFO) + +# Stream Handler (Quiet Detail for Terminal) +stream_handler = logging.StreamHandler() +stream_handler.setFormatter(log_formatter) +stream_handler.setLevel(logging.WARNING) # Only warnings/errors to terminal + logging.basicConfig( level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s', - handlers=[ - logging.FileHandler(log_file), - logging.StreamHandler() - ] + handlers=[file_handler, stream_handler] ) logger = logging.getLogger(__name__) diff --git a/video_transcription/ai_transcriber_v2/transcriber.py b/video_transcription/ai_transcriber_v2/transcriber.py index 2a3148f..ac01e43 100644 --- a/video_transcription/ai_transcriber_v2/transcriber.py +++ b/video_transcription/ai_transcriber_v2/transcriber.py @@ -3,18 +3,21 @@ import os import sys import subprocess import torch +import tracker def check_gpu_health(): """ Performs a robust check for GPU availability and prints detailed troubleshooting info if issues are detected, specific to Bazzite/VS Code environments. """ - print("Checking GPU health...") + tracker.logger.info("Checking GPU health...") # 1. Check if the OS/Driver sees the GPU nvidia_smi_ok = False try: - subprocess.run(["nvidia-smi"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True) + in_flatpak = os.path.exists("/.flatpak-info") + cmd = ["flatpak-spawn", "--host", "nvidia-smi"] if in_flatpak else ["nvidia-smi"] + subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True) nvidia_smi_ok = True except (subprocess.CalledProcessError, FileNotFoundError): nvidia_smi_ok = False @@ -23,36 +26,36 @@ def check_gpu_health(): torch_cuda_ok = torch.cuda.is_available() if torch_cuda_ok: - print(f"✅ GPU is accessible: {torch.cuda.get_device_name(0)}") - print(f" CUDA Version: {torch.version.cuda}") + tracker.logger.info(f"✅ GPU is accessible: {torch.cuda.get_device_name(0)}") + tracker.logger.info(f" CUDA Version: {torch.version.cuda}") return True # --- Troubleshooting Block --- - print("\n⚠️ WARNING: GPU not detected by PyTorch. Falling back to CPU.") - print(" Transcription will be significantly slower.\n") + tracker.logger.warning("\n⚠️ WARNING: GPU not detected by PyTorch. Falling back to CPU.") + tracker.logger.warning(" Transcription will be significantly slower.\n") - print("--- Diagnostic Report ---") + tracker.logger.info("--- Diagnostic Report ---") if nvidia_smi_ok: - print("1. [OK] 'nvidia-smi' command works. The system driver is installed and visible.") - print("2. [FAIL] PyTorch cannot see the GPU.") - print(" -> Likely Cause: You might have installed the CPU-only version of PyTorch.") - print(" -> Solution: Reinstall PyTorch with CUDA support:") - print(" pip uninstall torch torchvision torchaudio") - print(" pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118") + tracker.logger.info("1. [OK] 'nvidia-smi' command works. The system driver is installed and visible.") + tracker.logger.info("2. [FAIL] PyTorch cannot see the GPU.") + tracker.logger.info(" -> Likely Cause: You might have installed the CPU-only version of PyTorch.") + tracker.logger.info(" -> Solution: Reinstall PyTorch with CUDA support:") + tracker.logger.info(" pip uninstall torch torchvision torchaudio") + tracker.logger.info(" pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118") else: - print("1. [FAIL] 'nvidia-smi' command failed or not found.") - print(" -> Likely Cause: Nvidia drivers are missing, or the container/sandbox cannot access the GPU.") + tracker.logger.info("1. [FAIL] 'nvidia-smi' command failed or not found.") + tracker.logger.info(" -> Likely Cause: Nvidia drivers are missing, or the container/sandbox cannot access the GPU.") - print("\n --- Bazzite / VS Code / Container Specific Checks ---") - print(" a. If you are running inside a dev container (DevBox/Distrobox/Toolbox):") - print(" Ensure the container was created with nvidia support.") - print(" (Bazzite usually handles this for 'distrobox', but check your config).") - print(" b. If you are using VS Code Flatpak:") - print(" Flatpak might be restricting access. Check Flatseal permissions for VS Code.") - print(" c. Driver Check:") - print(" Run 'rpm -qa | grep nvidia' in your host terminal to verify drivers are installed.") + tracker.logger.info("\n --- Bazzite / VS Code / Container Specific Checks ---") + tracker.logger.info(" a. If you are running inside a dev container (DevBox/Distrobox/Toolbox):") + tracker.logger.info(" Ensure the container was created with nvidia support.") + tracker.logger.info(" (Bazzite usually handles this for 'distrobox', but check your config).") + tracker.logger.info(" b. If you are using VS Code Flatpak:") + tracker.logger.info(" Flatpak might be restricting access. Check Flatseal permissions for VS Code.") + tracker.logger.info(" c. Driver Check:") + tracker.logger.info(" Run 'rpm -qa | grep nvidia' in your host terminal to verify drivers are installed.") - print("-------------------------\n") + tracker.logger.info("-------------------------\n") return False def get_vram_gb(): @@ -80,7 +83,7 @@ def get_optimal_model_size(): if vram == 0: return "base" - print(f"Detected GPU with {vram:.2f} GB VRAM.") + tracker.logger.info(f"Detected GPU with {vram:.2f} GB VRAM.") if vram >= 11: return "large" @@ -113,7 +116,7 @@ def save_as_srt(result, output_path): f.write(f"{i}\n") f.write(f"{start} --> {end}\n") f.write(f"{text}\n\n") - print(f"SRT saved to: {output_path}") + tracker.logger.info(f"SRT saved to: {output_path}") def load_whisper_model(model_size="auto"): """ @@ -123,17 +126,17 @@ def load_whisper_model(model_size="auto"): if model_size == "auto": model_size = get_optimal_model_size() - print(f"Auto-selected model: '{model_size}'") + tracker.logger.info(f"Auto-selected model: '{model_size}'") - print(f"Loading Whisper model ('{model_size}')...") + tracker.logger.info(f"Loading Whisper model ('{model_size}')...") device = "cuda" if torch.cuda.is_available() else "cpu" - print(f"Using device: {device}") + tracker.logger.info(f"Using device: {device}") try: model = whisper.load_model(model_size, device=device) return model except Exception as e: - print(f"Error loading model: {e}") + tracker.logger.error(f"Error loading model: {e}") sys.exit(1) def transcribe_audio(audio_path, model_size="auto", language=None, loaded_model=None): @@ -156,12 +159,12 @@ def transcribe_audio(audio_path, model_size="auto", language=None, loaded_model= if model is None: model = load_whisper_model(model_size) - print(f"Transcribing {audio_path}...") + tracker.logger.info(f"Transcribing {audio_path}...") try: - # Enable verbose=True to show progress in terminal - result = model.transcribe(audio_path, language=language, verbose=True) - print("Transcription complete.") + # Disable verbose to prevent line-by-line output + result = model.transcribe(audio_path, language=language, verbose=False) + tracker.logger.info("Transcription complete.") return result except Exception as e: - print(f"Error during transcription: {e}") + tracker.logger.error(f"Error during transcription: {e}") sys.exit(1) diff --git a/video_transcription/ai_transcriber_v2/translator.py b/video_transcription/ai_transcriber_v2/translator.py index db38c65..1118fb5 100644 --- a/video_transcription/ai_transcriber_v2/translator.py +++ b/video_transcription/ai_transcriber_v2/translator.py @@ -25,8 +25,8 @@ def translate_via_ollama(source_srt_content, target_language="English", model="l subs = pysubs2.SSAFile.from_string(source_srt_content) # Using tqdm for progress bar - # dynamic_ncols=True helps it resize properly. leave=True ensures it stays after completion. - for line in tqdm(subs, desc=" Ollama Progress", unit="line", dynamic_ncols=True, leave=True): + # dynamic_ncols=True helps it resize properly. + for line in tqdm(subs, desc=" Ollama Progress", unit="line", dynamic_ncols=True, leave=False): text = line.text.strip() # Skip empty, numeric-only, or extremely short non-word text @@ -81,7 +81,7 @@ def translate_fallback_mymemory(source_srt_content, target_language="en"): # MyMemory uses ISO 639-1 usually translator = MyMemoryTranslator(source='auto', target=target_language) - for line in tqdm(subs, desc=" MyMemory Progress", unit="line"): + for line in tqdm(subs, desc=" MyMemory Progress", unit="line", leave=False): text = line.text.strip() # Skip empty, numeric-only, or extremely short non-word text @@ -121,7 +121,7 @@ def translate_fallback_free(source_srt_content, target_language="en"): translator = GoogleTranslator(source='auto', target=target_language) # Simple line-by-line translation - for line in tqdm(subs, desc=" DeepTranslate Progress", unit="line"): + for line in tqdm(subs, desc=" DeepTranslate Progress", unit="line", leave=False): text = line.text.strip() # Skip empty, numeric-only, or extremely short non-word text @@ -335,8 +335,8 @@ def translate_with_auto_fallback(srt_content, target_language="English", prefer_ # Execute attempts for i, method_func in enumerate(attempts): - if i > 0: - print(f" Attempt {i} failed. Trying next fallback...") + # if i > 0: + # print(f" Attempt {i} failed. Trying next fallback...") content, method = method_func() if content: