ricardo-lsantos commited on
Commit
7b2c089
·
1 Parent(s): 4b14b8d

Add initial project

Browse files
.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: app.py
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