Spaces:
Runtime error
Runtime error
Commit
·
7b2c089
1
Parent(s):
4b14b8d
Add initial project
Browse files- .gitignore +6 -0
- .streamlit/config.toml +294 -0
- Home.py +64 -0
- README.md +5 -1
- models/__init__.py +0 -0
- models/audio.py +16 -0
- models/file.py +8 -0
- models/subtitles.py +9 -0
- models/transcript.py +5 -0
- models/video.py +6 -0
- models/whisper.py +58 -0
- requirements.txt +5 -0
.gitignore
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.local
|
2 |
+
.vscode
|
3 |
+
.venv
|
4 |
+
output
|
5 |
+
input
|
6 |
+
__pycache__
|
.streamlit/config.toml
ADDED
@@ -0,0 +1,294 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Below are all the sections and options you can have in ~/.streamlit/config.toml.
|
2 |
+
|
3 |
+
|
4 |
+
[global]
|
5 |
+
|
6 |
+
# By default, Streamlit displays a warning when a user sets both a widget
|
7 |
+
# default value in the function defining the widget and a widget value via
|
8 |
+
# the widget's key in `st.session_state`.
|
9 |
+
|
10 |
+
# If you'd like to turn off this warning, set this to True.
|
11 |
+
|
12 |
+
# Default: false
|
13 |
+
# disableWidgetStateDuplicationWarning = false
|
14 |
+
|
15 |
+
# If True, will show a warning when you run a Streamlit-enabled script
|
16 |
+
# via "python my_script.py".
|
17 |
+
|
18 |
+
# Default: true
|
19 |
+
# showWarningOnDirectExecution = true
|
20 |
+
|
21 |
+
|
22 |
+
[logger]
|
23 |
+
|
24 |
+
# Level of logging: 'error', 'warning', 'info', or 'debug'.
|
25 |
+
|
26 |
+
# Default: 'info'
|
27 |
+
# level = "info"
|
28 |
+
|
29 |
+
# String format for logging messages. If logger.datetimeFormat is set,
|
30 |
+
# logger messages will default to `%(asctime)s.%(msecs)03d %(message)s`. See
|
31 |
+
# [Python's documentation](https://docs.python.org/2.6/library/logging.html#formatter-objects)
|
32 |
+
# for available attributes.
|
33 |
+
|
34 |
+
# Default: "%(asctime)s %(message)s"
|
35 |
+
# messageFormat = "%(asctime)s %(message)s"
|
36 |
+
|
37 |
+
|
38 |
+
[client]
|
39 |
+
|
40 |
+
# Controls whether uncaught app exceptions and deprecation warnings
|
41 |
+
# are displayed in the browser. By default, this is set to True and
|
42 |
+
# Streamlit displays app exceptions and associated tracebacks, and
|
43 |
+
# deprecation warnings, in the browser.
|
44 |
+
|
45 |
+
# If set to False, deprecation warnings and full exception messages
|
46 |
+
# will print to the console only. Exceptions will still display in the
|
47 |
+
# browser with a generic error message. For now, the exception type and
|
48 |
+
# traceback show in the browser also, but they will be removed in the
|
49 |
+
# future.
|
50 |
+
|
51 |
+
# Default: true
|
52 |
+
# showErrorDetails = true
|
53 |
+
|
54 |
+
# Change the visibility of items in the toolbar, options menu,
|
55 |
+
# and settings dialog (top right of the app).
|
56 |
+
|
57 |
+
# Allowed values:
|
58 |
+
# * "auto" : Show the developer options if the app is accessed through
|
59 |
+
# localhost or through Streamlit Community Cloud as a developer.
|
60 |
+
# Hide them otherwise.
|
61 |
+
# * "developer" : Show the developer options.
|
62 |
+
# * "viewer" : Hide the developer options.
|
63 |
+
# * "minimal" : Show only options set externally (e.g. through
|
64 |
+
# Streamlit Community Cloud) or through st.set_page_config.
|
65 |
+
# If there are no options left, hide the menu.
|
66 |
+
|
67 |
+
# Default: "auto"
|
68 |
+
# toolbarMode = "auto"
|
69 |
+
|
70 |
+
# Controls whether the default sidebar page navigation in a multi-page app is displayed.
|
71 |
+
|
72 |
+
# Default: true
|
73 |
+
# showSidebarNavigation = true
|
74 |
+
|
75 |
+
|
76 |
+
[runner]
|
77 |
+
|
78 |
+
# Allows you to type a variable or string by itself in a single line of
|
79 |
+
# Python code to write it to the app.
|
80 |
+
|
81 |
+
# Default: true
|
82 |
+
# magicEnabled = true
|
83 |
+
|
84 |
+
# Handle script rerun requests immediately, rather than waiting for script
|
85 |
+
# execution to reach a yield point. This makes Streamlit much more
|
86 |
+
# responsive to user interaction, but it can lead to race conditions in
|
87 |
+
# apps that mutate session_state data outside of explicit session_state
|
88 |
+
# assignment statements.
|
89 |
+
|
90 |
+
# Default: true
|
91 |
+
# fastReruns = true
|
92 |
+
|
93 |
+
# Raise an exception after adding unserializable data to Session State.
|
94 |
+
# Some execution environments may require serializing all data in Session
|
95 |
+
# State, so it may be useful to detect incompatibility during development,
|
96 |
+
# or when the execution environment will stop supporting it in the future.
|
97 |
+
|
98 |
+
# Default: false
|
99 |
+
# enforceSerializableSessionState = false
|
100 |
+
|
101 |
+
# Adjust how certain 'options' widgets like radio, selectbox, and
|
102 |
+
# multiselect coerce Enum members when the Enum class gets
|
103 |
+
# re-defined during a script re-run.
|
104 |
+
|
105 |
+
# Allowed values:
|
106 |
+
# * "off": Disables Enum coercion.
|
107 |
+
# * "nameOnly": Enum classes can be coerced if their member names match.
|
108 |
+
# * "nameAndValue": Enum classes can be coerced if their member names AND
|
109 |
+
# member values match.
|
110 |
+
|
111 |
+
# Default: "nameOnly"
|
112 |
+
# enumCoercion = "nameOnly"
|
113 |
+
|
114 |
+
|
115 |
+
[server]
|
116 |
+
|
117 |
+
# List of folders that should not be watched for changes. This
|
118 |
+
# impacts both "Run on Save" and @st.cache.
|
119 |
+
|
120 |
+
# Relative paths will be taken as relative to the current working directory.
|
121 |
+
|
122 |
+
# Example: ['/home/user1/env', 'relative/path/to/folder']
|
123 |
+
|
124 |
+
# Default: []
|
125 |
+
# folderWatchBlacklist = []
|
126 |
+
|
127 |
+
# Change the type of file watcher used by Streamlit, or turn it off
|
128 |
+
# completely.
|
129 |
+
|
130 |
+
# Allowed values:
|
131 |
+
# * "auto" : Streamlit will attempt to use the watchdog module, and
|
132 |
+
# falls back to polling if watchdog is not available.
|
133 |
+
# * "watchdog" : Force Streamlit to use the watchdog module.
|
134 |
+
# * "poll" : Force Streamlit to always use polling.
|
135 |
+
# * "none" : Streamlit will not watch files.
|
136 |
+
|
137 |
+
# Default: "auto"
|
138 |
+
# fileWatcherType = "auto"
|
139 |
+
|
140 |
+
# Symmetric key used to produce signed cookies. If deploying on multiple replicas, this should
|
141 |
+
# be set to the same value across all replicas to ensure they all share the same secret.
|
142 |
+
|
143 |
+
# Default: randomly generated secret key.
|
144 |
+
# cookieSecret = "75ce94a30d4b5d3c91b99ec42cca35d49077b6c620d9c20187e2ed8a64bf3053"
|
145 |
+
|
146 |
+
# If false, will attempt to open a browser window on start.
|
147 |
+
|
148 |
+
# Default: false unless (1) we are on a Linux box where DISPLAY is unset, or
|
149 |
+
# (2) we are running in the Streamlit Atom plugin.
|
150 |
+
# headless = false
|
151 |
+
|
152 |
+
# Automatically rerun script when the file is modified on disk.
|
153 |
+
|
154 |
+
# Default: false
|
155 |
+
# runOnSave = false
|
156 |
+
|
157 |
+
# The address where the server will listen for client and browser
|
158 |
+
# connections. Use this if you want to bind the server to a specific address.
|
159 |
+
# If set, the server will only be accessible from this address, and not from
|
160 |
+
# any aliases (like localhost).
|
161 |
+
|
162 |
+
# Default: (unset)
|
163 |
+
# address =
|
164 |
+
|
165 |
+
# The port where the server will listen for browser connections.
|
166 |
+
|
167 |
+
# Default: 8501
|
168 |
+
# port = 8501
|
169 |
+
|
170 |
+
# The base path for the URL where Streamlit should be served from.
|
171 |
+
|
172 |
+
# Default: ""
|
173 |
+
# baseUrlPath = ""
|
174 |
+
|
175 |
+
# Enables support for Cross-Origin Resource Sharing (CORS) protection, for added security.
|
176 |
+
|
177 |
+
# Due to conflicts between CORS and XSRF, if `server.enableXsrfProtection` is on and
|
178 |
+
# `server.enableCORS` is off at the same time, we will prioritize `server.enableXsrfProtection`.
|
179 |
+
|
180 |
+
# Default: true
|
181 |
+
# enableCORS = true
|
182 |
+
|
183 |
+
# Enables support for Cross-Site Request Forgery (XSRF) protection, for added security.
|
184 |
+
|
185 |
+
# Due to conflicts between CORS and XSRF, if `server.enableXsrfProtection` is on and
|
186 |
+
# `server.enableCORS` is off at the same time, we will prioritize `server.enableXsrfProtection`.
|
187 |
+
|
188 |
+
# Default: true
|
189 |
+
# enableXsrfProtection = true
|
190 |
+
|
191 |
+
# Max size, in megabytes, for files uploaded with the file_uploader.
|
192 |
+
|
193 |
+
# Default: 200
|
194 |
+
maxUploadSize = 2048
|
195 |
+
|
196 |
+
# Max size, in megabytes, of messages that can be sent via the WebSocket connection.
|
197 |
+
|
198 |
+
# Default: 200
|
199 |
+
maxMessageSize = 2048
|
200 |
+
|
201 |
+
# Enables support for websocket compression.
|
202 |
+
|
203 |
+
# Default: false
|
204 |
+
# enableWebsocketCompression = false
|
205 |
+
|
206 |
+
# Enable serving files from a `static` directory in the running app's directory.
|
207 |
+
|
208 |
+
# Default: false
|
209 |
+
# enableStaticServing = false
|
210 |
+
|
211 |
+
# Server certificate file for connecting via HTTPS.
|
212 |
+
# Must be set at the same time as "server.sslKeyFile".
|
213 |
+
|
214 |
+
# ['DO NOT USE THIS OPTION IN A PRODUCTION ENVIRONMENT. It has not gone through security audits or performance tests. For the production environment, we recommend performing SSL termination by the load balancer or the reverse proxy.']
|
215 |
+
# sslCertFile =
|
216 |
+
|
217 |
+
# Cryptographic key file for connecting via HTTPS.
|
218 |
+
# Must be set at the same time as "server.sslCertFile".
|
219 |
+
|
220 |
+
# ['DO NOT USE THIS OPTION IN A PRODUCTION ENVIRONMENT. It has not gone through security audits or performance tests. For the production environment, we recommend performing SSL termination by the load balancer or the reverse proxy.']
|
221 |
+
# sslKeyFile =
|
222 |
+
|
223 |
+
|
224 |
+
[browser]
|
225 |
+
|
226 |
+
# Internet address where users should point their browsers in order to
|
227 |
+
# connect to the app. Can be IP address or DNS name and path.
|
228 |
+
|
229 |
+
# This is used to:
|
230 |
+
# - Set the correct URL for CORS and XSRF protection purposes.
|
231 |
+
# - Show the URL on the terminal
|
232 |
+
# - Open the browser
|
233 |
+
|
234 |
+
# Default: "localhost"
|
235 |
+
# serverAddress = "localhost"
|
236 |
+
|
237 |
+
# Whether to send usage statistics to Streamlit.
|
238 |
+
|
239 |
+
# Default: true
|
240 |
+
# gatherUsageStats = true
|
241 |
+
|
242 |
+
# Port where users should point their browsers in order to connect to the
|
243 |
+
# app.
|
244 |
+
|
245 |
+
# This is used to:
|
246 |
+
# - Set the correct URL for CORS and XSRF protection purposes.
|
247 |
+
# - Show the URL on the terminal
|
248 |
+
# - Open the browser
|
249 |
+
|
250 |
+
# Default: whatever value is set in server.port.
|
251 |
+
# serverPort = 8501
|
252 |
+
|
253 |
+
|
254 |
+
[mapbox]
|
255 |
+
|
256 |
+
# Configure Streamlit to use a custom Mapbox
|
257 |
+
# token for elements like st.pydeck_chart and st.map.
|
258 |
+
# To get a token for yourself, create an account at
|
259 |
+
# https://mapbox.com. It's free (for moderate usage levels)!
|
260 |
+
|
261 |
+
# Default: ""
|
262 |
+
# token = ""
|
263 |
+
|
264 |
+
|
265 |
+
[deprecation]
|
266 |
+
|
267 |
+
# Set to false to disable the deprecation warning for using the global pyplot instance.
|
268 |
+
|
269 |
+
# Default: true
|
270 |
+
# showPyplotGlobalUse = true
|
271 |
+
|
272 |
+
|
273 |
+
[theme]
|
274 |
+
|
275 |
+
# The preset Streamlit theme that your custom theme inherits from.
|
276 |
+
# One of "light" or "dark".
|
277 |
+
# base =
|
278 |
+
|
279 |
+
# Primary accent color for interactive elements.
|
280 |
+
# primaryColor =
|
281 |
+
|
282 |
+
# Background color for the main content area.
|
283 |
+
# backgroundColor =
|
284 |
+
|
285 |
+
# Background color used for the sidebar and most interactive widgets.
|
286 |
+
# secondaryBackgroundColor =
|
287 |
+
|
288 |
+
# Color used for almost all text.
|
289 |
+
# textColor =
|
290 |
+
|
291 |
+
# Font family for all text in the app, except code blocks. One of "sans serif",
|
292 |
+
# "serif", or "monospace".
|
293 |
+
# font =
|
294 |
+
|
Home.py
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import models.file as mf
|
3 |
+
import models.video as mv
|
4 |
+
import models.whisper as mw
|
5 |
+
import models.subtitles as ms
|
6 |
+
import models.transcript as mt
|
7 |
+
|
8 |
+
def sidebar():
|
9 |
+
device = st.sidebar.selectbox('Select Device',('CPU','GPU'))
|
10 |
+
st.sidebar.write('You selected:', device)
|
11 |
+
return device
|
12 |
+
|
13 |
+
def load_model():
|
14 |
+
# if pipeline is in session state, return it
|
15 |
+
# else, load it and save it to session state
|
16 |
+
if 'pipeline' not in st.session_state:
|
17 |
+
device = mw.get_device()
|
18 |
+
st.session_state['pipeline'] = mw.get_pipe(device)
|
19 |
+
return st.session_state['pipeline']
|
20 |
+
|
21 |
+
def app():
|
22 |
+
device = sidebar()
|
23 |
+
pipeline = load_model()
|
24 |
+
st.title('Transcript Small Whisper')
|
25 |
+
st.write('Welcome to the Home page!')
|
26 |
+
|
27 |
+
file = st.file_uploader("Upload Files",type=['mp4','wav','mp3'])
|
28 |
+
|
29 |
+
progress_bar = st.progress(0)
|
30 |
+
status_text = st.empty()
|
31 |
+
|
32 |
+
if file is not None:
|
33 |
+
status_text.text('Uploading file...')
|
34 |
+
progress_bar.progress(10)
|
35 |
+
st.write(file.name)
|
36 |
+
status_text.text('File uploaded!')
|
37 |
+
file_details = {"FileName":file.name,"FileType":file.type,"FileSize":file.size}
|
38 |
+
st.write(file_details)
|
39 |
+
# st.write("type of file: ", type(file))
|
40 |
+
# st.write("Dir: ", dir(file))
|
41 |
+
# st.write("File: ", file.read())
|
42 |
+
if mf.get_file_type(file) == 'video':
|
43 |
+
status_text.text('Extracting audio from video...')
|
44 |
+
audio = mv.get_audio_from_video(file, file.name + '.mp3')
|
45 |
+
if mf.get_file_type(file) == 'audio':
|
46 |
+
status_text.text('Extracting audio from audio...')
|
47 |
+
audio = file.read()
|
48 |
+
progress_bar.progress(30)
|
49 |
+
status_text.text('Transcribing audio...')
|
50 |
+
transcript = mw.get_prediction(pipeline, audio)
|
51 |
+
progress_bar.progress(60)
|
52 |
+
status_text.text('Subtitling audio...')
|
53 |
+
subtitles = mw.get_prediction_with_timelines(transcript, file.name + '.srt')
|
54 |
+
progress_bar.progress(90)
|
55 |
+
status_text.text('Saving transcript...')
|
56 |
+
ms.save_subtitles(subtitles, file.name + '.srt')
|
57 |
+
status_text.text('Saving subtitles...')
|
58 |
+
mt.save_transcript(transcript, file.name + '.txt')
|
59 |
+
status_text.text('Done!')
|
60 |
+
progress_bar.progress(100)
|
61 |
+
|
62 |
+
|
63 |
+
if __name__ == '__main__':
|
64 |
+
app()
|
README.md
CHANGED
@@ -5,8 +5,12 @@ colorFrom: blue
|
|
5 |
colorTo: blue
|
6 |
sdk: streamlit
|
7 |
sdk_version: 1.30.0
|
8 |
-
app_file:
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
|
|
|
|
|
|
5 |
colorTo: blue
|
6 |
sdk: streamlit
|
7 |
sdk_version: 1.30.0
|
8 |
+
app_file: Home.py
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
13 |
+
|
14 |
+
# Transcript Small Whisper
|
15 |
+
|
16 |
+
Creates a Transcript and a Subtitle from Video or Audio
|
models/__init__.py
ADDED
File without changes
|
models/audio.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydub import AudioSegment
|
2 |
+
import os
|
3 |
+
import math
|
4 |
+
|
5 |
+
def split_audio(input_file, output_folder, duration):
|
6 |
+
audio = AudioSegment.from_mp3(input_file)
|
7 |
+
total_length = len(audio)
|
8 |
+
num_parts = math.ceil(total_length / (duration * 1000))
|
9 |
+
|
10 |
+
for i in range(num_parts):
|
11 |
+
start = i * duration * 1000
|
12 |
+
end = (i + 1) * duration * 1000
|
13 |
+
split_audio = audio[start:end]
|
14 |
+
output_path = os.path.join(output_folder, f"part_{i+1}.mp3")
|
15 |
+
split_audio.export(output_path, format="mp3")
|
16 |
+
print(f"Exported {output_path}")
|
models/file.py
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
def get_file_type(file):
|
2 |
+
if 'video' in file.type:
|
3 |
+
return 'video'
|
4 |
+
elif 'audio' in file.type:
|
5 |
+
return 'audio'
|
6 |
+
else:
|
7 |
+
return None
|
8 |
+
|
models/subtitles.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
def save_subtitles(prediction, output_file):
|
3 |
+
## Save prediction to subtitles file format
|
4 |
+
with open(output_file, "w") as f:
|
5 |
+
for i, chunk in enumerate(prediction):
|
6 |
+
f.write(f"{i+1}")
|
7 |
+
f.write(f"{chunk['timestamp'][0]} --> {chunk['timestamp'][1]}")
|
8 |
+
f.write(f"{chunk['text']}\n")
|
9 |
+
f.write("\n")
|
models/transcript.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
def save_transcript(prediction, output_file):
|
3 |
+
## Save prediction to subtitles file format
|
4 |
+
with open(output_file, "w") as f:
|
5 |
+
f.write(prediction)
|
models/video.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from moviepy.editor import *
|
2 |
+
|
3 |
+
def get_audio_from_video(input_file, output_folder):
|
4 |
+
video = VideoFileClip(input_file)
|
5 |
+
video.audio.write_audiofile(output_folder)
|
6 |
+
print(f"Exported {output_folder}")
|
models/whisper.py
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch_directml
|
2 |
+
from transformers import pipeline
|
3 |
+
|
4 |
+
MODEL_CHECKPOINT = "openai/whisper-small"
|
5 |
+
CHUNK_LENGTH_S = 30
|
6 |
+
|
7 |
+
def get_device():
|
8 |
+
# return "cpu"
|
9 |
+
return torch_directml.device()
|
10 |
+
|
11 |
+
def get_pipe(device, model_checkpoint=MODEL_CHECKPOINT, chunk_length_s=CHUNK_LENGTH_S):
|
12 |
+
return pipeline(
|
13 |
+
"automatic-speech-recognition",
|
14 |
+
model=model_checkpoint,
|
15 |
+
chunk_length_s=chunk_length_s,
|
16 |
+
device=device,
|
17 |
+
)
|
18 |
+
|
19 |
+
def get_prediction_with_timelines(pipe, sample):
|
20 |
+
return pipe(sample, batch_size=8, return_timestamps=True)["chunks"]
|
21 |
+
|
22 |
+
def get_prediction(pipe, sample):
|
23 |
+
return pipe(sample, batch_size=8)["text"]
|
24 |
+
|
25 |
+
|
26 |
+
# audio_file = open("movie.mp3", "rb")
|
27 |
+
# sample = audio_file.read()
|
28 |
+
# prediction = pipe(sample, batch_size=8, return_timestamps=True)["chunks"]
|
29 |
+
|
30 |
+
|
31 |
+
# def main():
|
32 |
+
# print("# Extracting audio from video")
|
33 |
+
# # audio = get_audio_from_video("movie.mp4", "movie.mp3")
|
34 |
+
# print("# Splitting audio into chunks")
|
35 |
+
# split_audio("movie.mp3", "movie_parts", 30)
|
36 |
+
# print("# Gettin Device")
|
37 |
+
# device = get_device()
|
38 |
+
# print("# Getting Pipeline")
|
39 |
+
# pipe = get_pipe(device)
|
40 |
+
# print("# Getting Predictions")
|
41 |
+
# for file in os.listdir("movie_parts"):
|
42 |
+
# print(f"Processing {file}")
|
43 |
+
# audio_file = open(os.path.join("movie_parts", file), "rb")
|
44 |
+
# sample = audio_file.read()
|
45 |
+
# print(f"# Getting Prediction for file {file}")
|
46 |
+
# prediction = get_prediction(pipe, sample)
|
47 |
+
# print(f"# Saving Subtitles for file {file}")
|
48 |
+
# save_subtitles(prediction, file.replace(".mp3", ".srt"))
|
49 |
+
# # Aggregating subtitles into one file
|
50 |
+
# print("# Aggregating subtitles into one file")
|
51 |
+
# with open("movie.srt", "w") as f:
|
52 |
+
# for file in os.listdir("movie_parts"):
|
53 |
+
# with open(os.path.join("movie_parts", file), "r") as f2:
|
54 |
+
# f.write(f2.read())
|
55 |
+
# print("# Done")
|
56 |
+
|
57 |
+
# if __name__ == "__main__":
|
58 |
+
# main()
|
requirements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
moviepy
|
3 |
+
pydub
|
4 |
+
torch
|
5 |
+
transformers
|