import gradio as gr from argparse import Namespace import os import shutil import sys import yt_dlp # для працы з YouTube import glob # Import glob for file searching GEMINI_API_KEY = os.getenv("gem2") from sub_tools.media.converter import hls_to_media, media_to_signature, video_to_audio from sub_tools.media.segmenter import segment_audio from sub_tools.subtitles.combiner import combine_subtitles from sub_tools.system.directory import change_directory from sub_tools.system.console import header, success, error from sub_tools.transcribe import transcribe # Вызначэнне функцый для дэактывацыі процілеглага поля def update_on_audio_change(audio): if audio is not None: return gr.update(interactive=False) return gr.update(interactive=True) def update_on_video_change(video): if video is not None: return gr.update(interactive=False) return gr.update(interactive=True) def main_logic(args: Namespace) -> tuple: """ Асноўная логіка прыкладання: ад загрузкі відэа/аўдыё да зліцця субтытраў. Пасля зліцця субтытраў вяртае (тэкст субтытраў, шлях да SRT‑файла для спампоўкі). """ output_str = "" subtitles_text = "" srt_file_path = None try: change_directory(args.output_path) step = 1 if "video" in args.tasks: if not args.hls_url: output_str += f"{step}. Download Video: No video file uploaded\n" raise Exception("No video file uploaded") header(f"{step}. Download Video") output_str += f"{step}. Download Video: Started\n" hls_to_media(args.hls_url, args.video_file, False, args.overwrite) success("Done!") output_str += "Done!\n" step += 1 if "audio" in args.tasks: header(f"{step}. Video to Audio") output_str += f"{step}. Video to Audio: Started\n" video_to_audio(args.video_file, args.audio_file, args.overwrite) success("Done!") output_str += "Done!\n" step += 1 if "signature" in args.tasks: header(f"{step}. Audio to Signature") output_str += f"{step}. Audio to Signature: Started\n" media_to_signature(args.audio_file, args.signature_file, args.overwrite) success("Done!") output_str += "Done!\n" step += 1 if "segment" in args.tasks: header(f"{step}. Segment Audio") output_str += f"{step}. Segment Audio: Started\n" print(f"Current working directory before segment_audio: {os.getcwd()}") # Debug CWD print(f"Audio file path for segmentation: {args.audio_file}") # Debug audio file path if not os.path.exists(args.audio_file): # Critical file existence check error_msg = f"Error: Audio file not found before segmentation: {args.audio_file}" error(error_msg) return (error_msg, None) print(f"Audio file exists before segmentation: {args.audio_file}") # Debug file existence segment_audio(args.audio_file, args.audio_segment_prefix, args.audio_segment_format, args.audio_segment_length, args.overwrite) success("Done!") output_str += "Done!\n" step += 1 if "transcribe" in args.tasks: if not (args.gemini_api_key and args.gemini_api_key.strip()): output_str += f"{step}. Transcribe Audio: No Gemini API Key provided\n" raise Exception("No Gemini API Key provided") header(f"{step}. Transcribe Audio") output_str += f"{step}. Transcribe Audio: Started\n" transcribe(args) success("Done!") output_str += "Done!\n" step += 1 if "combine" in args.tasks: header(f"{step}. Combine Subtitles") output_str += f"{step}. Combine Subtitles: Started\n" combine_subtitles(args.languages, args.audio_segment_prefix, args.audio_segment_format) success("Done!") output_str += "Done!\n" if args.languages: language = args.languages[0] srt_file_path = os.path.join(os.getcwd(), f"{language}.srt") try: with open(srt_file_path, "r", encoding="utf-8") as f: subtitles_text = f.read() except Exception as e: subtitles_text = f"Error reading subtitles file: {str(e)}" else: subtitles_text = "No language specified" step += 1 return (subtitles_text, srt_file_path) except Exception as e: error_msg = f"Error: {str(e)}" error(error_msg) return (error_msg, None) def run_subtools( tasks, hls_url, video_file, audio_file, signature_file, output_path, languages, overwrite, retry, gemini_api_key, debug, audio_segment_prefix, audio_segment_format, audio_segment_length ): """ Падрыхтоўка каталога вываду і запуск асноўнай логікі. """ if os.path.exists(output_path): shutil.rmtree(output_path) os.makedirs(output_path, exist_ok=True) if isinstance(languages, str): languages = [lang.strip() for lang in languages.split(",") if lang.strip()] args = Namespace( tasks=tasks, hls_url=hls_url, video_file=video_file, audio_file=audio_file, signature_file=signature_file, output_path=output_path, languages=languages, overwrite=overwrite, retry=retry, gemini_api_key=gemini_api_key, debug=debug, audio_segment_prefix=audio_segment_prefix, audio_segment_format=audio_segment_format, audio_segment_length=audio_segment_length, ) return main_logic(args) def transcribe_youtube(youtube_url: str) -> tuple: """ Спампоўвае аўдыё з відэа YouTube праз yt_dlp і вяртае паведамленне і шлях да часовага аўдыёфайла. Выкарыстоўвае chromewebstore.google.com_cookies.txt, калі ён ёсць. """ if not youtube_url: return "Не ўведзена спасылка", None output_dir = "output_youtube_downloads" # Define a specific output directory os.makedirs(output_dir, exist_ok=True) # Create the directory if it doesn't exist outtmpl = os.path.join(output_dir, "temp_youtube_audio.%(ext)s") # Path within the output dir try: ydl_opts = { 'format': 'bestaudio/best', 'outtmpl': outtmpl, #'quiet': True, # Прыбіраем quiet для адладкі 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', # Download as MP3 'preferredquality': '0', # лепшая якасць }], } default_cookies_file = "chromewebstore.google.com_cookies.txt" if os.path.exists(default_cookies_file): ydl_opts['cookiefile'] = default_cookies_file print(f"Выкарыстоўваецца файл cookie па змаўчанні: {default_cookies_file}") with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.download([youtube_url]) # Шукаем створаны аўдыёфайл у output_dir audio_files = glob.glob(os.path.join(output_dir, "temp_youtube_audio.*")) print(f"Знойдзеныя аўдыёфайлы ў {output_dir}: {audio_files}") # Дадаем вывад для адладкі if not audio_files: return ("Памылка: файл аўдыё не створаны", None) audio_file_rel = None # Relative path for f in audio_files: if f.endswith(".mp3"): audio_file_rel = f break if audio_file_rel is None: audio_file_rel = audio_files[0] audio_file_abs = os.path.abspath(audio_file_rel) # Get absolute path here! print(f"Абраны аўдыёфайл (relative): {audio_file_rel}") # Дадаем вывад для адладкі print(f"Абраны аўдыёфайл (absolute): {audio_file_abs}") # Дадаем вывад для адладкі return ("Спампоўка YouTube аўдыё завершана", audio_file_abs) # Return absolute path! except Exception as e: err_msg = f"Памылка пры апрацоўцы YouTube (yt_dlp): {e}. Калі ласка, пераканайцеся, што спасылка сапраўдная, і праверце, ці даступныя відэа." print(err_msg) return (err_msg, None) def process_youtube_url(youtube_url): """ Апрацоўвае YouTube спасылку: спампоўвае аўдыё, адлюстроўвае аўдыёфайл і запускае ланцуг апрацоўкі для стварэння субтытраў. """ download_msg, audio_file = transcribe_youtube(youtube_url) if not audio_file: return download_msg, None # Return None for other outputs if download fails full_audio_file_path = audio_file print(f"Поўны шлях да аўдыёфайла: {full_audio_file_path}") if not os.path.exists(full_audio_file_path): return f"Памылка: Аўдыёфайл не знойдзены па шляху: {full_audio_file_path}", None print(f"Файл існуе: {full_audio_file_path}") output_text_file, output_file_file = process_uploaded_file(audio=full_audio_file_path, video=None) return output_text_file, output_file_file # Correct return order: text, file_path def process_uploaded_file(audio, video): """ Выбірае, які файл загружаны, і фармуе параметры для апрацоўкі. Калі загружаны аўдыёфайл – запускае апрацоўку для аўдыё, калі відэафайл – запускае поўны ланцуг апрацоўкі. """ if audio is not None and video is None: tasks = ["signature", "segment", "transcribe", "combine"] video_file = "" # відэа не выкарыстоўваецца audio_file = audio hls_url = "" # не патрабуецца elif video is not None and audio is None: tasks = ["video", "audio", "signature", "segment", "transcribe", "combine"] video_file = video audio_file = "audio.mp3" # прызначаем імя для аўдыёфайла hls_url = "dummy" # задаём няпустое значэнне для праверкі else: return "Error: Загрузіце толькі АЎДЫЁ або ВІДЭАфайл, а не абодва.", None return run_subtools( tasks=tasks, hls_url=hls_url, video_file=video_file, audio_file=audio_file, signature_file="message.shazamsignature", output_path="output", languages="be", overwrite=False, retry=50, gemini_api_key=GEMINI_API_KEY, debug=True, audio_segment_prefix="audio_segment", audio_segment_format="mp3", audio_segment_length=300000 ) # --------------------- Gradio UI --------------------- with gr.Blocks() as demo: gr.Markdown("# пакуль не працуе! Транскрыпцыя аўдыя для беларускай мовы. Перарабляем на больш якаснае разпазнаванне для доўгіх відэа") gr.Markdown( """ ## [Можна выкарыстаць сэрвіс для кароткіх відэа тут] (https://huggingface.co/spaces/archivartaunik/SubtitlesBE) [Ёсць пытанні ці прапановы? Далучайцеся да беларускаймоўнай суполкі штучнага інтэлекту](https://t.me/belarusai) **Хочаце каб сэрвіс працаваў? Налівайце каву! :** [Buy me a coffee](https://buymeacoffee.com/tuteishygpt) **Агучце беларускую мову тут :** [Беларуская мадэль маўлення](https://huggingface.co/spaces/archivartaunik/Bextts) """ ) with gr.Tabs(): with gr.Tab("Файл"): with gr.Row(): audio_input = gr.Audio(type="filepath", label="Аўдыёфайл") # Keep type="filepath" video_input = gr.Video(label="Відэафайл", interactive=True) # Reset to interactive True initially audio_input.change(fn=update_on_audio_change, inputs=audio_input, outputs=video_input) video_input.change(fn=update_on_video_change, inputs=video_input, outputs=audio_input) submit_btn_file = gr.Button("Submit") output_text_file = gr.Textbox(label="Тэкст субтытраў") output_file_file = gr.File(label="Спампаваць SRT файл") submit_btn_file.click(fn=process_uploaded_file, inputs=[audio_input, video_input], outputs=[output_text_file, output_file_file]) with gr.Tab("YouTube"): youtube_url_input = gr.Textbox(label="YouTube URL", placeholder="Устаўце спасылку на відэа YouTube") submit_btn_youtube = gr.Button("Submit") output_text_youtube = gr.Textbox(label="Тэкст субтытраў") output_file_youtube = gr.File(label="Спампаваць SRT файл") submit_btn_youtube.click( fn=process_youtube_url, inputs=youtube_url_input, outputs=[output_text_youtube, output_file_youtube] # Correct output order ) demo.launch(allowed_paths=["output_youtube_downloads"])