Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -7,132 +7,145 @@ from pydub import AudioSegment
|
|
7 |
|
8 |
# Атрыманне ключоў і мадэляў з пераменных асяроддзя
|
9 |
GEMINI_API_KEY = os.getenv("gemini")
|
10 |
-
MODEL_NAME_TH = os.getenv("modTH")
|
11 |
-
MODEL_NAME = os.getenv(
|
12 |
-
|
|
|
|
|
|
|
|
|
13 |
|
14 |
-
# Стварэнне кліента з новым SDK
|
15 |
-
client = genai.Client(api_key=GEMINI_API_KEY)
|
16 |
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
try:
|
19 |
mime_type, _ = mimetypes.guess_type(audio_file)
|
20 |
-
if mime_type
|
21 |
-
return
|
|
|
|
|
|
|
|
|
22 |
with open(audio_file, "rb") as f:
|
23 |
audio_data = f.read()
|
24 |
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
30 |
)
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
transcript = "Не атрымалася транскрыбаваць аўдыя. Магчыма, памылка з API."
|
35 |
-
return transcript
|
36 |
except FileNotFoundError:
|
37 |
return "Памылка: Файл не знойдзены."
|
38 |
except Exception as e:
|
39 |
-
return f"Нечаканая памылка: {
|
|
|
40 |
|
41 |
-
def fix_subtitles_format(transcript):
|
42 |
-
"""
|
43 |
-
|
44 |
-
|
|
|
|
|
|
|
45 |
try:
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
)
|
50 |
-
response_fix = client.models.generate_content(
|
51 |
-
model=MODEL_NAME,
|
52 |
-
contents=prompt_fix,
|
53 |
-
generation_config=types.GenerationConfig() # Выкарыстоўваем правільны клас
|
54 |
-
)
|
55 |
-
if response_fix.text:
|
56 |
-
fixed_transcript = response_fix.text.strip()
|
57 |
-
else:
|
58 |
-
fixed_transcript = transcript # Калі памылка, вяртаем зыходны транскрыпт
|
59 |
-
return fixed_transcript
|
60 |
except Exception as e:
|
61 |
-
|
|
|
62 |
|
63 |
-
|
|
|
|
|
64 |
try:
|
65 |
with open(filename, "w", encoding="utf-8") as f:
|
66 |
f.write(transcript)
|
67 |
return transcript, filename
|
68 |
except Exception as e:
|
69 |
-
return f"Памылка пры запісе SRT-файла: {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
-
def process_audio(audio):
|
72 |
-
transcript = transcribe_audio(audio)
|
73 |
-
if transcript.startswith("Памылка") or transcript.startswith("Немагчыма"): # Больш поўная праверка памылак
|
74 |
-
return transcript, None
|
75 |
-
# Выпраўляем фармат часу ў субцітрах
|
76 |
fixed_transcript = fix_subtitles_format(transcript)
|
77 |
text, srt_file = create_srt(fixed_transcript)
|
78 |
return text, srt_file
|
79 |
|
80 |
-
|
|
|
|
|
81 |
try:
|
82 |
audio = AudioSegment.from_file(video_file)
|
83 |
audio_path = "extracted_audio.mp3"
|
84 |
audio.export(audio_path, format="mp3")
|
85 |
-
return audio_path,
|
86 |
except Exception as e:
|
87 |
-
return
|
|
|
88 |
|
89 |
-
def process_video(
|
90 |
-
|
|
|
91 |
if error:
|
92 |
-
return error,
|
93 |
return process_audio(audio_path)
|
94 |
|
95 |
-
def process_file(audio, video):
|
96 |
-
if audio is not None:
|
97 |
-
return process_audio(audio)
|
98 |
-
elif video is not None:
|
99 |
-
return process_video(video)
|
100 |
-
else:
|
101 |
-
return "Няма файла для апрацоўкі.", None
|
102 |
|
103 |
-
def
|
104 |
-
|
105 |
-
|
|
|
|
|
|
|
106 |
else:
|
107 |
-
return
|
|
|
|
|
|
|
|
|
|
|
108 |
|
109 |
-
def update_on_video_change(video):
|
110 |
-
if video is not None:
|
111 |
-
return gr.update(value=None, interactive=False)
|
112 |
-
else:
|
113 |
-
return gr.update(interactive=True)
|
114 |
|
115 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
try:
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
)
|
121 |
-
response = client.models.generate_content(
|
122 |
-
model=MODEL_NAME,
|
123 |
-
contents=prompt_text,
|
124 |
-
generation_config=types.GenerationConfig() # Выкары��тоўваем правільны клас
|
125 |
-
)
|
126 |
-
if response.text:
|
127 |
-
translated = response.text.strip()
|
128 |
-
else:
|
129 |
-
translated = "Не атрымалася перакласці тэкст. Магчыма, памылка з API."
|
130 |
translated_srt_filename = "translated_subtitles.srt"
|
131 |
-
|
132 |
-
f.write(translated)
|
133 |
-
return translated, translated_srt_filename
|
134 |
except Exception as e:
|
135 |
-
return f"Памылка пры перакладзе: {
|
|
|
|
|
136 |
|
137 |
with gr.Blocks() as demo:
|
138 |
gr.Markdown("# Транскрыпцыя аўдыя для беларускай мовы")
|
@@ -147,19 +160,28 @@ with gr.Blocks() as demo:
|
|
147 |
with gr.Row():
|
148 |
audio_input = gr.Audio(type="filepath", label="Аўдыёфайл")
|
149 |
video_input = gr.Video(label="Відэафайл")
|
150 |
-
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
|
153 |
btn = gr.Button("Апрацаваць")
|
154 |
transcript_output = gr.Textbox(label="Транскрыпцыя", lines=10)
|
155 |
file_output = gr.File(label="SRT-файл")
|
156 |
-
btn.click(
|
|
|
|
|
157 |
|
158 |
gr.Markdown("## Пераклад субцітраў")
|
159 |
with gr.Row():
|
160 |
language_dropdown = gr.Dropdown(
|
161 |
choices=["English", "Руcкая", "Польская", "Літоўская", "Нямецкая"],
|
162 |
-
label="Выберы мову перакладу",
|
|
|
163 |
)
|
164 |
translate_btn = gr.Button("Пераклад")
|
165 |
translation_output = gr.Textbox(label="Пераклад", lines=10)
|
@@ -167,7 +189,7 @@ with gr.Blocks() as demo:
|
|
167 |
translate_btn.click(
|
168 |
fn=translate_transcript,
|
169 |
inputs=[transcript_output, language_dropdown],
|
170 |
-
outputs=[translation_output, translation_file_output]
|
171 |
)
|
172 |
|
173 |
demo.launch()
|
|
|
7 |
|
8 |
# Атрыманне ключоў і мадэляў з пераменных асяроддзя
|
9 |
GEMINI_API_KEY = os.getenv("gemini")
|
10 |
+
MODEL_NAME_TH = os.getenv("modTH") # Мадэль для транскрыпцыі
|
11 |
+
MODEL_NAME = os.getenv(
|
12 |
+
"mod"
|
13 |
+
) # Мадэль для выпраўлення фармату і перакладу (можа быць той жа, што і modTH)
|
14 |
+
PROMPT_TRANSCRIBE = os.getenv(
|
15 |
+
"p"
|
16 |
+
) # Промпт для транскрыпцыі (лепш мець зразумелае імя)
|
17 |
|
|
|
|
|
18 |
|
19 |
+
# Стварэнне кліента (больш просты спосаб)
|
20 |
+
client = genai.GenerativeModel(model_name=MODEL_NAME_TH, api_key=GEMINI_API_KEY)
|
21 |
+
client_general = genai.GenerativeModel(model_name=MODEL_NAME, api_key=GEMINI_API_KEY)
|
22 |
+
|
23 |
+
|
24 |
+
def transcribe_audio(audio_file: str) -> str:
|
25 |
+
"""Транскрыбуе аўдыяфайл з дапамогай Google GenAI."""
|
26 |
try:
|
27 |
mime_type, _ = mimetypes.guess_type(audio_file)
|
28 |
+
if not mime_type or not mime_type.startswith("audio"):
|
29 |
+
return (
|
30 |
+
"Немагчыма вызначыць тып файла або файл не з'яўляецца аўдыяфайлам. "
|
31 |
+
"Падтрымліваюцца толькі аўдыяфайлы."
|
32 |
+
)
|
33 |
+
|
34 |
with open(audio_file, "rb") as f:
|
35 |
audio_data = f.read()
|
36 |
|
37 |
+
response = client.generate_content(
|
38 |
+
[
|
39 |
+
PROMPT_TRANSCRIBE,
|
40 |
+
{"mime_type": mime_type, "data": audio_data},
|
41 |
+
] # , # Промпт + дадзеныя
|
42 |
+
# generation_config=types.GenerationConfig( # можна задаць дадатковыя параметры, напр. temperature
|
43 |
+
# temperature=0.2,
|
44 |
+
# )
|
45 |
)
|
46 |
+
response.resolve() # Яўнае дазвол прамісаў (калі выкарыстоўваецца асінхронны рэжым)
|
47 |
+
return response.text.strip()
|
48 |
+
|
|
|
|
|
49 |
except FileNotFoundError:
|
50 |
return "Памылка: Файл не знойдзены."
|
51 |
except Exception as e:
|
52 |
+
return f"Нечаканая памылка: {e}"
|
53 |
+
|
54 |
|
55 |
+
def fix_subtitles_format(transcript: str) -> str:
|
56 |
+
"""Выпраўляе фармат часу ў субцітрах."""
|
57 |
+
prompt_fix = (
|
58 |
+
"Не змяняй тэксты, выправі толькі часовы фармат у субцітрах на правільны, "
|
59 |
+
"вось прыклад 00:00:01,589. \nУ адказ напішы толькі субцітры:\n"
|
60 |
+
f"{transcript}"
|
61 |
+
)
|
62 |
try:
|
63 |
+
response_fix = client_general.generate_content(prompt_fix)
|
64 |
+
response_fix.resolve()
|
65 |
+
return response_fix.text.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
except Exception as e:
|
67 |
+
print(f"Памылка пры выпраўленні субцітраў: {e}") # Лагіраванне памылкі
|
68 |
+
return transcript
|
69 |
|
70 |
+
|
71 |
+
def create_srt(transcript: str, filename: str = "subtitles.srt") -> tuple[str, str]:
|
72 |
+
"""Стварае SRT-файл з транскрыпцыі."""
|
73 |
try:
|
74 |
with open(filename, "w", encoding="utf-8") as f:
|
75 |
f.write(transcript)
|
76 |
return transcript, filename
|
77 |
except Exception as e:
|
78 |
+
return f"Памылка пры запісе SRT-файла: {e}", ""
|
79 |
+
|
80 |
+
|
81 |
+
def process_audio(audio_path: str) -> tuple[str, str]:
|
82 |
+
"""Апрацоўвае аўдыёфайл: транскрыбуе і стварае SRT."""
|
83 |
+
transcript = transcribe_audio(audio_path)
|
84 |
+
if transcript.startswith("Памылка") or transcript.startswith("Немагчыма"):
|
85 |
+
return transcript, "" # Пусты радок замест None для файла
|
86 |
|
|
|
|
|
|
|
|
|
|
|
87 |
fixed_transcript = fix_subtitles_format(transcript)
|
88 |
text, srt_file = create_srt(fixed_transcript)
|
89 |
return text, srt_file
|
90 |
|
91 |
+
|
92 |
+
def extract_audio_from_video(video_file: str) -> tuple[str, str]:
|
93 |
+
"""Выдзяляе аўдыёдарожку з відэафайла."""
|
94 |
try:
|
95 |
audio = AudioSegment.from_file(video_file)
|
96 |
audio_path = "extracted_audio.mp3"
|
97 |
audio.export(audio_path, format="mp3")
|
98 |
+
return audio_path, ""
|
99 |
except Exception as e:
|
100 |
+
return "", f"Памылка пры выдзяленні аўдыё з відэафайла: {e}"
|
101 |
+
|
102 |
|
103 |
+
def process_video(video_path: str) -> tuple[str, str]:
|
104 |
+
"""Апрацоўвае відэафайл: выдзяляе аўдыё, транскрыбуе і стварае SRT."""
|
105 |
+
audio_path, error = extract_audio_from_video(video_path)
|
106 |
if error:
|
107 |
+
return error, ""
|
108 |
return process_audio(audio_path)
|
109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
|
111 |
+
def process_file(audio_path: str | None, video_path: str | None) -> tuple[str, str]:
|
112 |
+
"""Апрацоўвае файл (аўдыё або відэа)."""
|
113 |
+
if audio_path:
|
114 |
+
return process_audio(audio_path)
|
115 |
+
elif video_path:
|
116 |
+
return process_video(video_path)
|
117 |
else:
|
118 |
+
return "Няма файла для апрацоўкі.", ""
|
119 |
+
|
120 |
+
|
121 |
+
def update_on_audio_change(audio_path: str | None) -> gr.update:
|
122 |
+
"""Абнаўляе інтэрфейс пры змене аўдыёфайла."""
|
123 |
+
return gr.update(value=None, interactive=not bool(audio_path))
|
124 |
|
|
|
|
|
|
|
|
|
|
|
125 |
|
126 |
+
def update_on_video_change(video_path: str | None) -> gr.update:
|
127 |
+
"""Абнаўляе інтэрфейс пры змене відэафайла."""
|
128 |
+
return gr.update(value=None, interactive=not bool(video_path))
|
129 |
+
|
130 |
+
|
131 |
+
def translate_transcript(
|
132 |
+
transcript: str, target_language: str
|
133 |
+
) -> tuple[str, str]:
|
134 |
+
"""Перакладае транскрыпцыю на іншую мову і стварае SRT."""
|
135 |
+
prompt_text = (
|
136 |
+
f"Перакладзі толькі тэксты субцітраў на {target_language} мову. "
|
137 |
+
"Астатняе пакінь як ёсць.\nТэкст:\n{transcript}"
|
138 |
+
)
|
139 |
try:
|
140 |
+
response = client_general.generate_content(prompt_text)
|
141 |
+
response.resolve()
|
142 |
+
translated = response.text.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
translated_srt_filename = "translated_subtitles.srt"
|
144 |
+
return create_srt(translated, translated_srt_filename) # Перавыкарыстанне create_srt
|
|
|
|
|
145 |
except Exception as e:
|
146 |
+
return f"Памылка пры перакладзе: {e}", ""
|
147 |
+
|
148 |
+
|
149 |
|
150 |
with gr.Blocks() as demo:
|
151 |
gr.Markdown("# Транскрыпцыя аўдыя для беларускай мовы")
|
|
|
160 |
with gr.Row():
|
161 |
audio_input = gr.Audio(type="filepath", label="Аўдыёфайл")
|
162 |
video_input = gr.Video(label="Відэафайл")
|
163 |
+
|
164 |
+
# Больш кампактны спосаб абнаўлення інтэрактыўнасці
|
165 |
+
audio_input.change(
|
166 |
+
fn=update_on_audio_change, inputs=audio_input, outputs=video_input
|
167 |
+
)
|
168 |
+
video_input.change(
|
169 |
+
fn=update_on_video_change, inputs=video_input, outputs=audio_input
|
170 |
+
)
|
171 |
|
172 |
btn = gr.Button("Апрацаваць")
|
173 |
transcript_output = gr.Textbox(label="Транскрыпцыя", lines=10)
|
174 |
file_output = gr.File(label="SRT-файл")
|
175 |
+
btn.click(
|
176 |
+
fn=process_file, inputs=[audio_input, video_input], outputs=[transcript_output, file_output]
|
177 |
+
)
|
178 |
|
179 |
gr.Markdown("## Пераклад субцітраў")
|
180 |
with gr.Row():
|
181 |
language_dropdown = gr.Dropdown(
|
182 |
choices=["English", "Руcкая", "Польская", "Літоўская", "Нямецкая"],
|
183 |
+
label="Выберы мову перакладу",
|
184 |
+
value="English",
|
185 |
)
|
186 |
translate_btn = gr.Button("Пераклад")
|
187 |
translation_output = gr.Textbox(label="Пераклад", lines=10)
|
|
|
189 |
translate_btn.click(
|
190 |
fn=translate_transcript,
|
191 |
inputs=[transcript_output, language_dropdown],
|
192 |
+
outputs=[translation_output, translation_file_output],
|
193 |
)
|
194 |
|
195 |
demo.launch()
|