Spaces:
Sleeping
Sleeping
sync with github
Browse files- README.md +17 -1
- annotator/__init__.py +0 -0
- annotator/utils.py +10 -13
- app.py +43 -27
- dev-requirements.txt +1 -0
- requirements.txt +5 -3
README.md
CHANGED
@@ -9,4 +9,20 @@ app_file: app.py
|
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
+
## Try the app on hf-spaces
|
13 |
+
|
14 |
+
You can find the deployed app → [**here**](https://huggingface.co/spaces/deven367/yt-video-annotator/)
|
15 |
+
|
16 |
+
> **Note**
|
17 |
+
> The app inference is slow as the inference is running on a CPU, if you have GPU on your local system, the app will work a lot faster.
|
18 |
+
|
19 |
+
## Installation
|
20 |
+
|
21 |
+
1. Create a virtual env with the environment manager of your choice
|
22 |
+
2. Activate the environment
|
23 |
+
3. Install the dependencies using ```pip install -e .```
|
24 |
+
4. To run the app locally in your terminal, type `run_app`
|
25 |
+
|
26 |
+
## Contributing
|
27 |
+
|
28 |
+
Issues and PRs are welcome. If you want me to implement a feature, create a Feature Request in the issues, I'll try my best to implement it.
|
annotator/__init__.py
ADDED
File without changes
|
annotator/utils.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1 |
-
import whisper
|
2 |
import datetime
|
3 |
-
import pandas as pd
|
4 |
-
import numpy as np
|
5 |
import subprocess
|
6 |
-
from fastcore.foundation import working_directory, L
|
7 |
from pathlib import Path
|
|
|
|
|
|
|
8 |
import torch
|
|
|
|
|
9 |
|
10 |
|
11 |
def start_app():
|
@@ -16,7 +17,7 @@ def get_audio(url: str):
|
|
16 |
audio_path = Path("./audio")
|
17 |
with working_directory(audio_path):
|
18 |
# subprocess.run(['youtube-dl', '-F', 'bestaudio[ext=m4a]', url])
|
19 |
-
subprocess.run(["
|
20 |
|
21 |
def get_v_from_url(url):
|
22 |
_, val = url.split('?v=')
|
@@ -36,14 +37,10 @@ def get_time(seconds):
|
|
36 |
|
37 |
|
38 |
def df_from_result(result):
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
return df
|
44 |
-
except:
|
45 |
-
return None
|
46 |
-
|
47 |
|
48 |
|
49 |
def find_word_timestamp(df, *words):
|
|
|
|
|
1 |
import datetime
|
|
|
|
|
2 |
import subprocess
|
|
|
3 |
from pathlib import Path
|
4 |
+
|
5 |
+
import numpy as np
|
6 |
+
import pandas as pd
|
7 |
import torch
|
8 |
+
import whisper
|
9 |
+
from fastcore.foundation import L, working_directory
|
10 |
|
11 |
|
12 |
def start_app():
|
|
|
17 |
audio_path = Path("./audio")
|
18 |
with working_directory(audio_path):
|
19 |
# subprocess.run(['youtube-dl', '-F', 'bestaudio[ext=m4a]', url])
|
20 |
+
subprocess.run(["yt-dlp", "-x", "--audio-format", "wav", url])
|
21 |
|
22 |
def get_v_from_url(url):
|
23 |
_, val = url.split('?v=')
|
|
|
37 |
|
38 |
|
39 |
def df_from_result(result):
|
40 |
+
df = pd.json_normalize(result["segments"])
|
41 |
+
df["start"] = df["start"].apply(get_time)
|
42 |
+
df["end"] = df["end"].apply(get_time)
|
43 |
+
return df
|
|
|
|
|
|
|
|
|
44 |
|
45 |
|
46 |
def find_word_timestamp(df, *words):
|
app.py
CHANGED
@@ -1,54 +1,70 @@
|
|
|
|
|
|
|
|
1 |
import streamlit as st
|
2 |
-
from annotator.utils import *
|
3 |
-
st.set_page_config(layout='wide')
|
4 |
from fastcore.xtras import globtastic
|
5 |
-
from pathlib import Path
|
6 |
-
import subprocess
|
7 |
|
8 |
-
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
-
|
12 |
-
if not
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
|
15 |
def make_sidebar():
|
16 |
with st.sidebar:
|
17 |
-
st.markdown(
|
18 |
-
st.write(
|
|
|
19 |
|
20 |
-
@st.
|
21 |
def caption_from_url(url):
|
22 |
audio_src = get_audio(url)
|
23 |
v = get_v_from_url(url)
|
24 |
-
audio_src = globtastic(AUDIO_PATH, file_glob=
|
25 |
result = annotate(audio_src)
|
26 |
df = df_from_result(result)
|
27 |
return audio_src, df
|
28 |
|
29 |
|
30 |
-
|
31 |
-
|
32 |
def main():
|
33 |
url, name = None, None
|
34 |
make_sidebar()
|
35 |
-
place =
|
36 |
col1, col2 = st.columns([1.2, 1])
|
37 |
with col1:
|
38 |
-
url = st.text_input(
|
39 |
st.video(url)
|
40 |
|
41 |
with col2:
|
42 |
-
default_opt =
|
43 |
-
opt = st.radio(
|
|
|
|
|
|
|
44 |
if opt == default_opt:
|
45 |
-
st.markdown(
|
46 |
-
words = st.text_input(
|
47 |
-
words = words.split(
|
48 |
|
49 |
-
if st.button(
|
50 |
audio_src, df = caption_from_url(url)
|
51 |
-
st.write(df)
|
52 |
times = find_word_timestamp(df, *words)
|
53 |
times = np.asarray(times).reshape(len(words), -1)
|
54 |
# st.write(times)
|
@@ -56,7 +72,7 @@ def main():
|
|
56 |
st.write(f"{word} is said on {times[i].flatten()} timestamp")
|
57 |
|
58 |
else:
|
59 |
-
if st.button(
|
60 |
audio_src, df = caption_from_url(url)
|
61 |
name = Path(audio_src).stem
|
62 |
s = generate_srt(df)
|
@@ -66,13 +82,13 @@ def main():
|
|
66 |
if name is not None:
|
67 |
with working_directory(SRT_PATH):
|
68 |
key = get_v_from_url(url)
|
69 |
-
srt = globtastic(
|
70 |
with open(srt) as f:
|
71 |
-
st.download_button(
|
72 |
|
73 |
# subprocess.run(['rm', '-rf', 'audio'])
|
74 |
# subprocess.run(['rm', '-rf', 'srt'])
|
75 |
|
76 |
|
77 |
if __name__ == "__main__":
|
78 |
-
main()
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
|
3 |
+
import numpy as np
|
4 |
import streamlit as st
|
|
|
|
|
5 |
from fastcore.xtras import globtastic
|
|
|
|
|
6 |
|
7 |
+
from annotator.utils import (
|
8 |
+
annotate,
|
9 |
+
df_from_result,
|
10 |
+
find_word_timestamp,
|
11 |
+
generate_srt,
|
12 |
+
get_audio,
|
13 |
+
get_v_from_url,
|
14 |
+
working_directory,
|
15 |
+
write_srt,
|
16 |
+
)
|
17 |
+
|
18 |
+
st.set_page_config(layout="wide")
|
19 |
+
|
20 |
|
21 |
+
SRT_PATH = Path("srt")
|
22 |
+
if not SRT_PATH.exists():
|
23 |
+
SRT_PATH.mkdir()
|
24 |
+
|
25 |
+
AUDIO_PATH = Path("./audio")
|
26 |
+
if not AUDIO_PATH.exists():
|
27 |
+
AUDIO_PATH.mkdir()
|
28 |
|
29 |
|
30 |
def make_sidebar():
|
31 |
with st.sidebar:
|
32 |
+
st.markdown("## yt-video-annotator")
|
33 |
+
st.write("Link to the GitHub repo")
|
34 |
+
|
35 |
|
36 |
+
@st.cache_resource
|
37 |
def caption_from_url(url):
|
38 |
audio_src = get_audio(url)
|
39 |
v = get_v_from_url(url)
|
40 |
+
audio_src = globtastic(AUDIO_PATH, file_glob="*.mp3", file_re=v)[0]
|
41 |
result = annotate(audio_src)
|
42 |
df = df_from_result(result)
|
43 |
return audio_src, df
|
44 |
|
45 |
|
|
|
|
|
46 |
def main():
|
47 |
url, name = None, None
|
48 |
make_sidebar()
|
49 |
+
place = "https://www.youtube.com/watch?v=C0DPdy98e4c&ab_channel=SimonYapp"
|
50 |
col1, col2 = st.columns([1.2, 1])
|
51 |
with col1:
|
52 |
+
url = st.text_input("Enter URL for the YT video", place)
|
53 |
st.video(url)
|
54 |
|
55 |
with col2:
|
56 |
+
default_opt = "Search for words"
|
57 |
+
opt = st.radio(
|
58 |
+
"What do you wish to do?",
|
59 |
+
[default_opt, "Generate subtitles for the entire video"],
|
60 |
+
)
|
61 |
if opt == default_opt:
|
62 |
+
st.markdown("### Search for words in the video")
|
63 |
+
words = st.text_input("Enter words separated by a comma")
|
64 |
+
words = words.split(",")
|
65 |
|
66 |
+
if st.button("Get Timestamps"):
|
67 |
audio_src, df = caption_from_url(url)
|
|
|
68 |
times = find_word_timestamp(df, *words)
|
69 |
times = np.asarray(times).reshape(len(words), -1)
|
70 |
# st.write(times)
|
|
|
72 |
st.write(f"{word} is said on {times[i].flatten()} timestamp")
|
73 |
|
74 |
else:
|
75 |
+
if st.button("Generate SRT"):
|
76 |
audio_src, df = caption_from_url(url)
|
77 |
name = Path(audio_src).stem
|
78 |
s = generate_srt(df)
|
|
|
82 |
if name is not None:
|
83 |
with working_directory(SRT_PATH):
|
84 |
key = get_v_from_url(url)
|
85 |
+
srt = globtastic(".", file_glob="*.srt", file_re=key)[0]
|
86 |
with open(srt) as f:
|
87 |
+
st.download_button("Download SRT", f, file_name=f"{name}.srt")
|
88 |
|
89 |
# subprocess.run(['rm', '-rf', 'audio'])
|
90 |
# subprocess.run(['rm', '-rf', 'srt'])
|
91 |
|
92 |
|
93 |
if __name__ == "__main__":
|
94 |
+
main()
|
dev-requirements.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
black==23.10.0
|
requirements.txt
CHANGED
@@ -1,3 +1,5 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
|
|
|
|
|
1 |
+
fastcore==1.5.29
|
2 |
+
yt-dlp==2023.10.13
|
3 |
+
openai-whisper==20230314
|
4 |
+
streamlit==1.25.0
|
5 |
+
|