Add application file
Browse files- .streamlit/secrets.toml +12 -0
- app.py +126 -0
- requirements.txt +94 -0
.streamlit/secrets.toml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
open_ai = "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"
|
| 2 |
+
serp = "bd4187d5f23e6a405a6470fe4fe03e61742cccf4"
|
| 3 |
+
brwoserless = "0af8da42-e7eb-4c99-a98e-34d924416991"
|
| 4 |
+
anthropic = "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"
|
| 5 |
+
|
| 6 |
+
xi_api_key = "6d5e981fbb2643b06459981da55c4ae7"
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
twilio_ssid = "AC892f3e7e653e2b4b8f5d03d916c036b5"
|
| 10 |
+
twilio_auth = "6e8ca23b01873d18e1ba3c896fefa531"
|
| 11 |
+
Twilio_from_number = "whatsapp:+14155238886"
|
| 12 |
+
Zalpier_nla = "sk-ak-OVFYaWalqbjFPGFFnRcrvQf8Vu"
|
app.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import whisper
|
| 3 |
+
from pytube import YouTube
|
| 4 |
+
from pydub import AudioSegment
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import anthropic
|
| 7 |
+
from anthropic import Anthropic, HUMAN_PROMPT, AI_PROMPT
|
| 8 |
+
import io
|
| 9 |
+
from elevenlabs import generate, set_api_key
|
| 10 |
+
import subprocess
|
| 11 |
+
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
|
| 12 |
+
import os
|
| 13 |
+
from elevenlabs import set_api_key
|
| 14 |
+
|
| 15 |
+
set_api_key("6d5e981fbb2643b06459981da55c4ae7")
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def shorten_audio(filename):
|
| 19 |
+
cut_filename = "AutoDub/dub/cut_audio.mp4"
|
| 20 |
+
audio = AudioSegment.from_file(filename)
|
| 21 |
+
cut_audio = audio[:60 * 1000]
|
| 22 |
+
cut_audio.export(cut_filename, format="mp4")
|
| 23 |
+
return cut_filename
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def generate_translation(original_text, destination_language):
|
| 27 |
+
anthropic = Anthropic(
|
| 28 |
+
api_key="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")
|
| 29 |
+
|
| 30 |
+
prompt = (
|
| 31 |
+
f"{HUMAN_PROMPT} Please translate this video transcript into {destination_language}. You will get "
|
| 32 |
+
f"to the translation directly after I prompted 'the translation:'"
|
| 33 |
+
f"{AI_PROMPT} Understood, I will get to the translation without any opening lines."
|
| 34 |
+
f"{HUMAN_PROMPT} Great! this is the transcript: {original_text}; the translation:"
|
| 35 |
+
)
|
| 36 |
+
|
| 37 |
+
resp = anthropic.completions.create(
|
| 38 |
+
prompt=f"{prompt} {AI_PROMPT}",
|
| 39 |
+
model="claude-2.0",
|
| 40 |
+
stop_sequences=[HUMAN_PROMPT],
|
| 41 |
+
max_tokens_to_sample=900,
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
print(resp.completion)
|
| 45 |
+
|
| 46 |
+
return resp.completion
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def generate_dubs(text):
|
| 50 |
+
filename = "AutoDub/dub/output.mp3"
|
| 51 |
+
|
| 52 |
+
set_api_key(st.secrets['xi_api_key'])
|
| 53 |
+
|
| 54 |
+
audio = generate(
|
| 55 |
+
text=text,
|
| 56 |
+
voice="Sanchay",
|
| 57 |
+
model='eleven_multilingual_v1'
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
audio_io = io.BytesIO(audio)
|
| 61 |
+
insert_audio = AudioSegment.from_file(audio_io, format='mp3')
|
| 62 |
+
insert_audio.export(filename, format="mp3")
|
| 63 |
+
|
| 64 |
+
return filename
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def combine_video(video_filename, audio_filename):
|
| 68 |
+
ffmpeg_extract_subclip(video_filename, 0, 60, targetname="cut_video.mp4")
|
| 69 |
+
|
| 70 |
+
output_filename = "AutoDub/dub/output.mp4"
|
| 71 |
+
|
| 72 |
+
command = ["ffmpeg", "-y", "-i", "cut_video.mp4", "-i", audio_filename, "-c:v", "copy", "-c:a", "aac",
|
| 73 |
+
output_filename]
|
| 74 |
+
|
| 75 |
+
subprocess.run(command)
|
| 76 |
+
|
| 77 |
+
return output_filename
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
st.title("AutoDubs 📺🎵")
|
| 81 |
+
|
| 82 |
+
link = st.text_input("Link to Youtube Video", key="link")
|
| 83 |
+
|
| 84 |
+
language = st.selectbox("Translate to", ("French", "German", "Hindi", "Italian", "Polish", "Portuguese", "Spanish"))
|
| 85 |
+
|
| 86 |
+
if st.button("Transcribe!"):
|
| 87 |
+
print(f"downloading from link: {link}")
|
| 88 |
+
|
| 89 |
+
model = whisper.load_model("base")
|
| 90 |
+
|
| 91 |
+
yt = YouTube(link)
|
| 92 |
+
|
| 93 |
+
if yt is not None:
|
| 94 |
+
st.subheader(yt.title)
|
| 95 |
+
st.image(yt.thumbnail_url)
|
| 96 |
+
audio_name = st.caption("Downloading audio stream...")
|
| 97 |
+
audio_streams = yt.streams.filter(only_audio=True)
|
| 98 |
+
filename = audio_streams.first().download()
|
| 99 |
+
print("filename: ", filename)
|
| 100 |
+
|
| 101 |
+
if filename:
|
| 102 |
+
audio_name.caption(filename)
|
| 103 |
+
cut_filename = shorten_audio(filename)
|
| 104 |
+
transcription = model.transcribe(cut_filename)
|
| 105 |
+
print(transcription)
|
| 106 |
+
|
| 107 |
+
if transcription:
|
| 108 |
+
df = pd.DataFrame(transcription['segments'], columns=['start', 'end', 'text'])
|
| 109 |
+
st.dataframe(df)
|
| 110 |
+
print(transcription['text'])
|
| 111 |
+
dubbing_caption = st.caption("Dubbing...")
|
| 112 |
+
translation = generate_translation(transcription['text'], language)
|
| 113 |
+
dubbing_caption = st.caption("Begin dubbing...")
|
| 114 |
+
dubs_audio = generate_dubs(translation)
|
| 115 |
+
dubbing_caption.caption("Dubs generated! combining with the video...")
|
| 116 |
+
|
| 117 |
+
video_streams = yt.streams.filter(only_video=True)
|
| 118 |
+
video_filename = video_streams.first().download()
|
| 119 |
+
|
| 120 |
+
if video_filename:
|
| 121 |
+
dubbing_caption.caption("Video downloaded! combining the video and the dubs...")
|
| 122 |
+
output_filename = combine_video(video_filename, dubs_audio)
|
| 123 |
+
|
| 124 |
+
if os.path.exists(output_filename):
|
| 125 |
+
dubbing_caption.caption("Video successfully dubbed! Enjoy! 😀")
|
| 126 |
+
st.video(output_filename)
|
requirements.txt
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
altair==5.0.1
|
| 2 |
+
anthropic==0.3.6
|
| 3 |
+
anyio==3.7.1
|
| 4 |
+
appnope==0.1.3
|
| 5 |
+
asttokens==2.2.1
|
| 6 |
+
attrs==23.1.0
|
| 7 |
+
backcall==0.2.0
|
| 8 |
+
blinker==1.6.2
|
| 9 |
+
cachetools==5.3.1
|
| 10 |
+
certifi==2023.7.22
|
| 11 |
+
charset-normalizer==3.2.0
|
| 12 |
+
click==8.1.6
|
| 13 |
+
decorator==4.4.2
|
| 14 |
+
distro==1.8.0
|
| 15 |
+
elevenlabs==0.2.21
|
| 16 |
+
executing==1.2.0
|
| 17 |
+
ffmpeg-python==0.2.0
|
| 18 |
+
filelock==3.12.2
|
| 19 |
+
future==0.18.3
|
| 20 |
+
gitdb==4.0.10
|
| 21 |
+
GitPython==3.1.32
|
| 22 |
+
h11==0.14.0
|
| 23 |
+
httpcore==0.17.3
|
| 24 |
+
httpx==0.24.1
|
| 25 |
+
idna==3.4
|
| 26 |
+
imageio==2.31.1
|
| 27 |
+
imageio-ffmpeg==0.4.8
|
| 28 |
+
importlib-metadata==6.8.0
|
| 29 |
+
ipython==8.14.0
|
| 30 |
+
jedi==0.18.2
|
| 31 |
+
Jinja2==3.1.2
|
| 32 |
+
jsonschema==4.18.4
|
| 33 |
+
jsonschema-specifications==2023.7.1
|
| 34 |
+
llvmlite==0.40.1
|
| 35 |
+
markdown-it-py==3.0.0
|
| 36 |
+
MarkupSafe==2.1.3
|
| 37 |
+
matplotlib-inline==0.1.6
|
| 38 |
+
mdurl==0.1.2
|
| 39 |
+
more-itertools==10.0.0
|
| 40 |
+
moviepy==1.0.3
|
| 41 |
+
mpmath==1.3.0
|
| 42 |
+
networkx==3.1
|
| 43 |
+
numba==0.57.1
|
| 44 |
+
numpy==1.24.4
|
| 45 |
+
openai-whisper==20230314
|
| 46 |
+
packaging==23.1
|
| 47 |
+
pandas==2.0.3
|
| 48 |
+
parso==0.8.3
|
| 49 |
+
pexpect==4.8.0
|
| 50 |
+
pickleshare==0.7.5
|
| 51 |
+
Pillow==9.5.0
|
| 52 |
+
proglog==0.1.10
|
| 53 |
+
prompt-toolkit==3.0.39
|
| 54 |
+
protobuf==4.23.4
|
| 55 |
+
ptyprocess==0.7.0
|
| 56 |
+
pure-eval==0.2.2
|
| 57 |
+
pyarrow==12.0.1
|
| 58 |
+
pydantic==1.10.12
|
| 59 |
+
pydeck==0.8.0
|
| 60 |
+
pydub==0.25.1
|
| 61 |
+
Pygments==2.15.1
|
| 62 |
+
Pympler==1.0.1
|
| 63 |
+
python-dateutil==2.8.2
|
| 64 |
+
pytube==15.0.0
|
| 65 |
+
pytz==2023.3
|
| 66 |
+
pytz-deprecation-shim==0.1.0.post0
|
| 67 |
+
referencing==0.30.0
|
| 68 |
+
regex==2023.6.3
|
| 69 |
+
requests==2.31.0
|
| 70 |
+
rich==13.4.2
|
| 71 |
+
rpds-py==0.9.2
|
| 72 |
+
six==1.16.0
|
| 73 |
+
smmap==5.0.0
|
| 74 |
+
sniffio==1.3.0
|
| 75 |
+
stack-data==0.6.2
|
| 76 |
+
streamlit==1.25.0
|
| 77 |
+
sympy==1.12
|
| 78 |
+
tenacity==8.2.2
|
| 79 |
+
tiktoken==0.3.1
|
| 80 |
+
tokenizers==0.13.3
|
| 81 |
+
toml==0.10.2
|
| 82 |
+
toolz==0.12.0
|
| 83 |
+
torch==2.0.1
|
| 84 |
+
tornado==6.3.2
|
| 85 |
+
tqdm==4.65.0
|
| 86 |
+
traitlets==5.9.0
|
| 87 |
+
typing_extensions==4.7.1
|
| 88 |
+
tzdata==2023.3
|
| 89 |
+
tzlocal==4.3.1
|
| 90 |
+
urllib3==2.0.4
|
| 91 |
+
validators==0.20.0
|
| 92 |
+
wcwidth==0.2.6
|
| 93 |
+
whisper==1.1.10
|
| 94 |
+
zipp==3.16.2
|