SubtitlesBE / app.py
archivartaunik's picture
Update app.py
82ff83b verified
raw
history blame
10.9 kB
import os
import gradio as gr
from google import genai
from google.genai import types
import mimetypes
from pydub import AudioSegment
import asyncio
import logging
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Атрыманне ключоў і мадэляў з пераменных асяроддзя
GEMINI_API_KEY = os.getenv("gemini")
MODEL_NAME_TH = os.getenv("modTH") # Мадэль для транскрыпцыі
MODEL_NAME = os.getenv("mod") # Мадэль для выпраўлення фармату і перакладу
PROMPT_TRANSCRIBE = os.getenv("p") # Промпт для транскрыпцыі
# Стварэнне кліента
client = genai.Client(api_key=GEMINI_API_KEY)
def transcribe_audio(audio_file: str) -> str:
"""Транскрыбуе аўдыяфайл з дапамогай Google GenAI."""
try:
if not audio_file or not os.path.exists(audio_file):
return "Памылка: Файл не знойдзены або не указаны."
mime_type, _ = mimetypes.guess_type(audio_file)
if not mime_type or not mime_type.startswith("audio"):
return (
"Немагчыма вызначыць тып файла або файл не з'яўляецца аўдыяфайлам. "
"Падтрымліваюцца толькі аўдыяфайлы."
)
with open(audio_file, "rb") as f:
audio_data = f.read()
# Стварэнне contents для перадачы ў API
contents = [
{"text": PROMPT_TRANSCRIBE},
{"mime_type": mime_type, "data": audio_data},
]
# Выклік API
response = client.models.generate_content(
model=MODEL_NAME_TH,
contents=contents,
config={"temperature": 0.2}
)
# Атрыманне адказу
return response.text.strip()
except FileNotFoundError:
logger.error(f"Файл не знойдзены: {audio_file}")
return "Памылка: Файл не знойдзены."
except Exception as e:
logger.error(f"Памылка пры транскрыпцыі: {str(e)}", exc_info=True)
return f"Нечаканая памылка: {str(e)}"
def fix_subtitles_format(transcript: str) -> str:
"""Выпраўляе фармат часу ў субцітрах."""
if not transcript:
return ""
prompt_fix = (
"Не змяняй тэксты, выправі толькі часовы фармат у субцітрах на правільны, "
"вось прыклад 00:00:01,589. \nУ адказ напішы толькі субцітры:\n"
f"{transcript}"
)
try:
response_fix = client.models.generate_content(
model=MODEL_NAME,
contents=[{"text": prompt_fix}],
config={"temperature": 0.2}
)
return response_fix.text.strip()
except Exception as e:
logger.error(f"Памылка пры выпраўленні субцітраў: {str(e)}", exc_info=True)
return transcript
def create_srt(transcript: str, filename: str = "subtitles.srt") -> tuple[str, str]:
"""Стварае SRT-файл з транскрыпцыі."""
if not transcript:
return "", ""
try:
with open(filename, "w", encoding="utf-8") as f:
f.write(transcript)
return transcript, filename
except Exception as e:
logger.error(f"Памылка пры запісе SRT-файла: {str(e)}", exc_info=True)
return f"Памылка пры запісе SRT-файла: {str(e)}", ""
def process_audio(audio_path: str) -> tuple[str, str]:
"""Апрацоўвае аўдыёфайл: транскрыбуе і стварае SRT."""
if not audio_path:
return "Не указаны шлях да аўдыёфайла.", ""
transcript = transcribe_audio(audio_path)
if transcript.startswith("Памылка") or transcript.startswith("Немагчыма") or transcript.startswith("Нечаканая"):
return transcript, ""
fixed_transcript = fix_subtitles_format(transcript)
text, srt_file = create_srt(fixed_transcript)
return text, srt_file
def extract_audio_from_video(video_file: str) -> tuple[str, str]:
"""Выдзяляе аўдыёдарожку з відэафайла."""
if not video_file or not os.path.exists(video_file):
return "", "Памылка: Відэафайл не знойдзены або не указаны."
try:
audio = AudioSegment.from_file(video_file)
audio_path = "extracted_audio.mp3"
audio.export(audio_path, format="mp3")
return audio_path, ""
except Exception as e:
logger.error(f"Памылка пры выдзяленні аўдыё з відэафайла: {str(e)}", exc_info=True)
return "", f"Памылка пры выдзяленні аўдыё з відэафайла: {str(e)}"
def process_video(video_path: str) -> tuple[str, str]:
"""Апрацоўвае відэафайл: выдзяляе аўдыё, транскрыбуе і стварае SRT."""
if not video_path:
return "Не указаны шлях да відэафайла.", ""
audio_path, error = extract_audio_from_video(video_path)
if error:
return error, ""
return process_audio(audio_path)
def process_file(audio_path: str | None, video_path: str | None) -> tuple[str, str]:
"""Апрацоўвае файл (аўдыё або відэа)."""
try:
if audio_path:
return process_audio(audio_path)
elif video_path:
return process_video(video_path)
else:
return "Няма файла для апрацоўкі.", ""
except Exception as e:
logger.error(f"Памылка пры апрацоўцы файла: {str(e)}", exc_info=True)
return f"Памылка пры апрацоўцы файла: {str(e)}", ""
def update_on_audio_change(audio_path: str | None) -> gr.update:
"""Абнаўляе інтэрфейс пры змене аўдыёфайла."""
try:
return gr.update(value=None, interactive=not bool(audio_path))
except Exception as e:
logger.error(f"Памылка пры абнаўленні інтэрфейса: {str(e)}", exc_info=True)
return gr.update(value=None, interactive=True)
def update_on_video_change(video_path: str | None) -> gr.update:
"""Абнаўляе інтэрфейс пры змене відэафайла."""
try:
return gr.update(value=None, interactive=not bool(video_path))
except Exception as e:
logger.error(f"Памылка пры абнаўленні інтэрфейса: {str(e)}", exc_info=True)
return gr.update(value=None, interactive=True)
def translate_transcript(transcript: str, target_language: str) -> tuple[str, str]:
"""Перакладае транскрыпцыю на іншую мову і стварае SRT."""
if not transcript:
return "Няма тэксту для перакладу.", ""
prompt_text = (
f"Перакладзі толькі тэксты субцітраў на {target_language} мову. "
"Астатняе пакінь як ёсць.\nТэкст:\n{transcript}"
)
try:
response = client.models.generate_content(
model=MODEL_NAME,
contents=[{"text": prompt_text}],
config={"temperature": 0.2}
)
translated = response.text.strip()
translated_srt_filename = "translated_subtitles.srt"
return create_srt(translated, translated_srt_filename)
except Exception as e:
logger.error(f"Памылка пры перакладзе: {str(e)}", exc_info=True)
return f"Памылка пры перакладзе: {str(e)}", ""
try:
with gr.Blocks() as demo:
gr.Markdown("# Транскрыпцыя аўдыя для беларускай мовы")
gr.Markdown(
"""
## Загрузіце аўдыёфайл або відэафайл да 15 хвілін. Калі загружаны аўдыёфайл, відэа неактыўна, і наадварот.
Субцітры будуць аўтаматычна згенераваны разам з SRT-файлам.
[Далучайцеся да беларускаймоўнай суполкі ў ТГ](https://t.me/belarusai)
**Падтрымаць праект:** [Buy me a coffee](https://buymeacoffee.com/tuteishygpt)
"""
)
with gr.Row():
audio_input = gr.Audio(type="filepath", label="Аўдыёфайл")
video_input = gr.Video(label="Відэафайл")
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
)
btn = gr.Button("Апрацаваць")
transcript_output = gr.Textbox(label="Транскрыпцыя", lines=10)
file_output = gr.File(label="SRT-файл")
btn.click(
fn=process_file, inputs=[audio_input, video_input], outputs=[transcript_output, file_output]
)
gr.Markdown("## Пераклад субцітраў")
with gr.Row():
language_dropdown = gr.Dropdown(
choices=["English", "Руcкая", "Польская", "Літоўская", "Нямецкая"],
label="Выберы мову перакладу",
value="English",
)
translate_btn = gr.Button("Пераклад")
translation_output = gr.Textbox(label="Пераклад", lines=10)
translation_file_output = gr.File(label="Translated SRT-файл")
translate_btn.click(
fn=translate_transcript,
inputs=[transcript_output, language_dropdown],
outputs=[translation_output, translation_file_output],
)
# Запуск з дадатковымі параметрамі для стабільнасці
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
debug=False,
show_error=True,
prevent_thread_lock=True
)
except Exception as e:
logger.critical(f"Крытычная памылка пры запуску праграмы: {str(e)}", exc_info=True)
print(f"Крытычная памылка: {str(e)}")