Spaces:
Running
Running
Subtitle support added
Browse files
app.py
CHANGED
|
@@ -316,12 +316,61 @@ def voice_cloning(segments, audio_path, max_threads=2):
|
|
| 316 |
|
| 317 |
def set_processing(value=True):
|
| 318 |
st.session_state.is_processing = value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
if __name__ == "__main__":
|
| 320 |
if "is_processing" not in st.session_state:
|
| 321 |
st.session_state.is_processing = False
|
| 322 |
|
| 323 |
with st.sidebar:
|
| 324 |
-
|
| 325 |
st.write("Language Options")
|
| 326 |
input_languages = [
|
| 327 |
("Japanese", "ja"), ("English", "en"), ("Chinese", "zh"),
|
|
@@ -359,17 +408,27 @@ if __name__ == "__main__":
|
|
| 359 |
args=(True,)
|
| 360 |
)
|
| 361 |
st.divider()
|
| 362 |
-
|
| 363 |
st.write("Transcription Options")
|
| 364 |
whisper_models = ["tiny", "base", "small",
|
| 365 |
"medium", "large", "large-v2", "large-v3", "turbo"]
|
| 366 |
selected_model = st.selectbox(
|
| 367 |
"Select Whisper model for transcription",
|
| 368 |
options=whisper_models,
|
| 369 |
-
index=
|
| 370 |
disabled=st.session_state.is_processing,
|
| 371 |
help="Larger models provide better accuracy but are slower."
|
| 372 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
|
| 374 |
# Show current device info
|
| 375 |
st.info(f"🖥️ Using device: **{device.upper()}**" +
|
|
@@ -484,8 +543,13 @@ if __name__ == "__main__":
|
|
| 484 |
[translated_audio, bg_audio, drums_audio, bass_audio])
|
| 485 |
|
| 486 |
video = video.with_audio(combined_audio)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
dubbed_video_path = os.path.join(
|
| 488 |
sample_output_dir, f"dubbed_video_{selected_model}_{output_language.lower()}.mp4")
|
|
|
|
| 489 |
video.write_videofile(
|
| 490 |
dubbed_video_path,
|
| 491 |
codec="libx264",
|
|
@@ -495,7 +559,10 @@ if __name__ == "__main__":
|
|
| 495 |
remove_temp=True
|
| 496 |
)
|
| 497 |
st.subheader("Dubbed video")
|
| 498 |
-
st.
|
|
|
|
|
|
|
|
|
|
| 499 |
end_time = time.time()
|
| 500 |
# # Calculate the elapsed time
|
| 501 |
elapsed_time = end_time - start_time
|
|
|
|
| 316 |
|
| 317 |
def set_processing(value=True):
|
| 318 |
st.session_state.is_processing = value
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
def generate_srt_subtitles(segments, output_path, subtitle_type="translation"):
|
| 322 |
+
"""
|
| 323 |
+
Generate SRT subtitle file from segments
|
| 324 |
+
subtitle_type: "translation" for dubbed text, "original" for original text
|
| 325 |
+
"""
|
| 326 |
+
try:
|
| 327 |
+
with open(output_path, 'w', encoding='utf-8') as srt_file:
|
| 328 |
+
for i, segment in enumerate(segments, 1):
|
| 329 |
+
start_time = segment["start"]
|
| 330 |
+
end_time = segment["end"]
|
| 331 |
+
|
| 332 |
+
# Convert seconds to SRT time format (HH:MM:SS,mmm)
|
| 333 |
+
start_srt = seconds_to_srt_time(start_time)
|
| 334 |
+
end_srt = seconds_to_srt_time(end_time)
|
| 335 |
+
|
| 336 |
+
# Choose text based on subtitle type
|
| 337 |
+
if subtitle_type == "translation" and "translation" in segment:
|
| 338 |
+
text = segment["translation"]
|
| 339 |
+
elif "text" in segment:
|
| 340 |
+
text = segment["text"]
|
| 341 |
+
else:
|
| 342 |
+
text = "..." # Fallback for empty segments
|
| 343 |
+
|
| 344 |
+
# Clean up text for SRT format
|
| 345 |
+
text = text.replace('\n', ' ').strip()
|
| 346 |
+
if not text:
|
| 347 |
+
continue # Skip empty segments
|
| 348 |
+
|
| 349 |
+
# Write SRT entry
|
| 350 |
+
srt_file.write(f"{i}\n")
|
| 351 |
+
srt_file.write(f"{start_srt} --> {end_srt}\n")
|
| 352 |
+
srt_file.write(f"{text}\n\n")
|
| 353 |
+
|
| 354 |
+
return output_path
|
| 355 |
+
except Exception as e:
|
| 356 |
+
st.error(f"Failed to generate subtitles: {e}")
|
| 357 |
+
return None
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
def seconds_to_srt_time(seconds):
|
| 361 |
+
"""Convert seconds to SRT time format (HH:MM:SS,mmm)"""
|
| 362 |
+
hours = int(seconds // 3600)
|
| 363 |
+
minutes = int((seconds % 3600) // 60)
|
| 364 |
+
secs = int(seconds % 60)
|
| 365 |
+
milliseconds = int((seconds % 1) * 1000)
|
| 366 |
+
return f"{hours:02d}:{minutes:02d}:{secs:02d},{milliseconds:03d}"
|
| 367 |
+
|
| 368 |
+
# Main Streamlit app
|
| 369 |
if __name__ == "__main__":
|
| 370 |
if "is_processing" not in st.session_state:
|
| 371 |
st.session_state.is_processing = False
|
| 372 |
|
| 373 |
with st.sidebar:
|
|
|
|
| 374 |
st.write("Language Options")
|
| 375 |
input_languages = [
|
| 376 |
("Japanese", "ja"), ("English", "en"), ("Chinese", "zh"),
|
|
|
|
| 408 |
args=(True,)
|
| 409 |
)
|
| 410 |
st.divider()
|
| 411 |
+
|
| 412 |
st.write("Transcription Options")
|
| 413 |
whisper_models = ["tiny", "base", "small",
|
| 414 |
"medium", "large", "large-v2", "large-v3", "turbo"]
|
| 415 |
selected_model = st.selectbox(
|
| 416 |
"Select Whisper model for transcription",
|
| 417 |
options=whisper_models,
|
| 418 |
+
index=7, # Default to 'large'
|
| 419 |
disabled=st.session_state.is_processing,
|
| 420 |
help="Larger models provide better accuracy but are slower."
|
| 421 |
)
|
| 422 |
+
st.divider()
|
| 423 |
+
|
| 424 |
+
st.write("Subtitle Control")
|
| 425 |
+
st.toggle(
|
| 426 |
+
"Enable subtitles",
|
| 427 |
+
value=True,
|
| 428 |
+
key="enable_subtitles",
|
| 429 |
+
disabled=st.session_state.is_processing,
|
| 430 |
+
help="Enable or disable subtitles in the dubbed video."
|
| 431 |
+
)
|
| 432 |
|
| 433 |
# Show current device info
|
| 434 |
st.info(f"🖥️ Using device: **{device.upper()}**" +
|
|
|
|
| 543 |
[translated_audio, bg_audio, drums_audio, bass_audio])
|
| 544 |
|
| 545 |
video = video.with_audio(combined_audio)
|
| 546 |
+
dubbed_video_file_name = f"dubbed_video_{selected_model}_{output_language.lower()}.mp4"
|
| 547 |
+
subtitle_path = os.path.join(
|
| 548 |
+
sample_output_dir, f"dubbed_video_{selected_model}_{output_language.lower()}.srt")
|
| 549 |
+
# Embed subtitles in the video
|
| 550 |
dubbed_video_path = os.path.join(
|
| 551 |
sample_output_dir, f"dubbed_video_{selected_model}_{output_language.lower()}.mp4")
|
| 552 |
+
generate_srt_subtitles(segments, subtitle_path)
|
| 553 |
video.write_videofile(
|
| 554 |
dubbed_video_path,
|
| 555 |
codec="libx264",
|
|
|
|
| 559 |
remove_temp=True
|
| 560 |
)
|
| 561 |
st.subheader("Dubbed video")
|
| 562 |
+
if st.session_state.enable_subtitles:
|
| 563 |
+
st.video(dubbed_video_path, subtitles=subtitle_path)
|
| 564 |
+
else:
|
| 565 |
+
st.video(dubbed_video_path)
|
| 566 |
end_time = time.time()
|
| 567 |
# # Calculate the elapsed time
|
| 568 |
elapsed_time = end_time - start_time
|