Akhil commited on
Commit
747252f
·
1 Parent(s): 8cf0316

minor change

Browse files
__pycache__/main.cpython-312.pyc DELETED
Binary file (13.3 kB)
 
__pycache__/main.cpython-313.pyc DELETED
Binary file (14.4 kB)
 
main.py → app.py RENAMED
@@ -1,292 +1,292 @@
1
- from faster_whisper import WhisperModel, BatchedInferencePipeline
2
- import time
3
- import os
4
- import yt_dlp
5
- import subprocess
6
- from typing import Optional
7
- import logging
8
- from fastapi import FastAPI, File, UploadFile, HTTPException, Form
9
- from fastapi.responses import FileResponse
10
- import os, time
11
- from fastapi.middleware.cors import CORSMiddleware
12
- from pathlib import Path
13
- import zipfile
14
- import tempfile
15
-
16
-
17
- app = FastAPI()
18
-
19
- app.add_middleware(
20
- CORSMiddleware,
21
- allow_origins=["http://localhost:5173", "http://127.0.0.1:5173"],
22
- allow_credentials=True,
23
- allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
24
- allow_headers=["*"],
25
- )
26
-
27
- logging.basicConfig()
28
- logging.getLogger("faster_whisper").setLevel(logging.DEBUG)
29
-
30
- def youtube_download_video(VIDEO_URL, DOWNLOAD_DIR, output_template):
31
- URLS = [VIDEO_URL]
32
- os.makedirs(DOWNLOAD_DIR, exist_ok=True)
33
-
34
- ydl_opts = {
35
- 'outtmpl': output_template,
36
- 'format': 'bestvideo[height<=1080]+bestaudio/best',
37
- 'merge_output_format': 'mp4',
38
- 'verbose': True
39
- }
40
-
41
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
42
- try:
43
- print(f"Downloading from YouTube: {URLS[0]}")
44
- info = ydl.extract_info(URLS[0], download=True)
45
- if not info:
46
- return "Error downloading youtube video"
47
-
48
- final_filepath = None
49
- if 'requested_downloads' in info and info['requested_downloads']:
50
- final_filepath = info['requested_downloads'][0]['filepath']
51
- elif '_filename' in info:
52
- final_filepath = info['_filename']
53
- else:
54
- print("Warning: yt-dlp did not provide a clear filepath. Attempting to construct.")
55
- if 'title' in info and 'ext' in info:
56
- guessed_filename = f"{info['title']}.{info['ext']}"
57
- guessed_path = os.path.join(DOWNLOAD_DIR, guessed_filename)
58
- if os.path.exists(guessed_path):
59
- final_filepath = guessed_path
60
- else:
61
- print(f"Could not determine downloaded file path for {URLS[0]}.")
62
-
63
- except Exception as e:
64
- print(f"An error occurred during YouTube download: {e}")
65
- final_filepath = None
66
- finally:
67
- return final_filepath
68
-
69
- def local_audio_file(DOWNLOAD_DIR, AUDIO_FILE):
70
- try:
71
- potential_path = os.path.join(DOWNLOAD_DIR, AUDIO_FILE)
72
- if os.path.exists(potential_path):
73
- final_filepath = potential_path
74
- print(f"Using local file: {final_filepath}")
75
- elif os.path.exists(AUDIO_FILE):
76
- final_filepath = AUDIO_FILE
77
- print(f"Using local file: {final_filepath}")
78
- else:
79
- print(f"Local file not found at '{potential_path}' or as '{AUDIO_FILE}'")
80
- final_filepath = None
81
- except Exception as e:
82
- final_path = None
83
- print(f"Error finding file:{e}")
84
- finally:
85
- return final_filepath
86
-
87
- def create_subtitle_chunks(segments, max_words=8, max_duration=5.0):
88
- subtitle_chunks = []
89
-
90
- for segment in segments:
91
- if hasattr(segment, 'words') and segment.words:
92
- current_chunk = []
93
- chunk_start = segment.words[0].start
94
-
95
- for i, word in enumerate(segment.words):
96
- current_chunk.append(word.word)
97
-
98
- if (len(current_chunk) >= max_words or
99
- word.end - chunk_start >= max_duration):
100
-
101
- text = ''.join(current_chunk).strip()
102
- subtitle_chunks.append({
103
- 'start': chunk_start,
104
- 'end': word.end,
105
- 'text': text
106
- })
107
-
108
- current_chunk = []
109
- if i + 1 < len(segment.words):
110
- chunk_start = segment.words[i + 1].start
111
-
112
- if current_chunk:
113
- text = ''.join(current_chunk).strip()
114
- subtitle_chunks.append({
115
- 'start': chunk_start,
116
- 'end': segment.words[-1].end,
117
- 'text': text
118
- })
119
- else:
120
- subtitle_chunks.append({
121
- 'start': segment.start,
122
- 'end': segment.end,
123
- 'text': segment.text
124
- })
125
-
126
- return subtitle_chunks
127
-
128
- def format_time(seconds):
129
- seconds -= 0.2
130
- hours = int(seconds // 3600)
131
- minutes = int((seconds % 3600) // 60)
132
- seconds_remainder = seconds % 60
133
- milliseconds = int((seconds_remainder - int(seconds_remainder)) * 1000)
134
-
135
- return f"{hours:02d}:{minutes:02d}:{int(seconds_remainder):02d},{milliseconds:03d}"
136
-
137
- def add_subtitles(media_path):
138
- base, ext = os.path.splitext(os.path.basename(media_path))
139
- dir_path = os.path.dirname(media_path)
140
-
141
- final_output = os.path.join(dir_path, f"{base}_subtitled.mp4")
142
- subtitle_file = os.path.join(dir_path, f"{base}.srt")
143
-
144
- if not os.path.exists(subtitle_file):
145
- print(f"Error: Subtitle file not found at {subtitle_file}")
146
- return
147
-
148
- video_formats = ['.mp4', '.webm', '.mpeg']
149
-
150
- try:
151
- if ext.lower() in video_formats:
152
- print('Found video file.')
153
-
154
- temp_output = os.path.join(dir_path, f"{base}_temp.mp4")
155
- cmd = ['ffmpeg', '-i', media_path, '-i', subtitle_file, '-c', 'copy', '-c:s', 'mov_text', temp_output, '-y']
156
-
157
- subprocess.run(cmd, check=True, capture_output=True)
158
-
159
- if ext.lower() == ".mp4":
160
- os.remove(media_path)
161
- os.rename(temp_output, media_path)
162
- else:
163
- os.rename(temp_output, final_output)
164
- else:
165
- print('Found audio file.')
166
- temp_video = os.path.join(dir_path, f"{base}_temp.mp4")
167
- cmd1 = ['ffmpeg', '-f', 'lavfi', '-i', 'color=c=black:s=1280x720:r=5',
168
- '-i', media_path, '-c:a', 'copy', '-shortest', temp_video, '-y']
169
- subprocess.run(cmd1, check=True, capture_output=True)
170
-
171
- cmd2 = ['ffmpeg', '-i', temp_video, '-i', subtitle_file, '-c',
172
- 'copy', '-c:s', 'mov_text', final_output, '-y']
173
- subprocess.run(cmd2, check=True, capture_output=True)
174
- os.remove(temp_video)
175
-
176
- return final_output
177
-
178
- except subprocess.CalledProcessError as e:
179
- print(f"FFmpeg Error: {e.stderr.decode()}")
180
- except Exception as e:
181
- print(f"An error occurred: {e}")
182
-
183
- @app.get('/test')
184
- async def test_endpoint():
185
- return {"message": "FastAPI is working!"}
186
-
187
- @app.post('/generate-subtitles')
188
- async def generate_subtitles(
189
- file: Optional[UploadFile] = File(None),
190
- youtube_url: Optional[str] = Form(None)
191
- ):
192
-
193
- upload_dir = 'audio'
194
- os.makedirs(upload_dir, exist_ok=True)
195
-
196
- if file:
197
- file_path = os.path.join(upload_dir, file.filename)
198
- with open(file_path, "wb") as f:
199
- f.write(await file.read())
200
- final_filepath = file_path
201
- print(f"Uploaded file saved to {final_filepath}")
202
- elif youtube_url:
203
- output_template = os.path.join(upload_dir, "%(title)s.%(ext)s")
204
- final_filepath = youtube_download_video(youtube_url, upload_dir, output_template)
205
- else:
206
- raise HTTPException(status_code=400, detail="You must provide either a file or youtube URL.")
207
-
208
-
209
- if final_filepath and os.path.exists(final_filepath):
210
- print(f"Processing audio file: {final_filepath}")
211
- print(f"File size: {os.path.getsize(final_filepath) / 1024 / 1024:.2f} MB")
212
-
213
- base_name = os.path.basename(final_filepath)
214
- file_name_without_extension, _ = os.path.splitext(base_name)
215
-
216
- FILE_NAME_FOR_TXT = file_name_without_extension
217
- MODEL_NAME = "small"
218
-
219
- print(f"\nLoading Whisper model: {MODEL_NAME}...")
220
- try:
221
- model_path = os.path.join('models', 'snapshots', '536b0662742c02347bc0e980a01041f333bce120')
222
- model = WhisperModel(model_path, device="cpu", compute_type="int8")
223
- batched_model = BatchedInferencePipeline(model=model)
224
- print("Model loaded successfully.")
225
-
226
- print("\nStarting transcription...")
227
- start_time = time.time()
228
-
229
- segments, info = batched_model.transcribe(
230
- final_filepath,
231
- batch_size=8,
232
- beam_size=5,
233
- word_timestamps=True
234
- )
235
-
236
- os.makedirs(upload_dir, exist_ok=True)
237
- transcript_filename = os.path.join(upload_dir, f"{FILE_NAME_FOR_TXT}.srt")
238
-
239
- subtitle_chunks = create_subtitle_chunks(segments, max_words=12, max_duration=4.0)
240
-
241
- full_transcript_text = []
242
- for chunk in subtitle_chunks:
243
- start_time_formatted = format_time(chunk['start'])
244
- end_time_formatted = format_time(chunk['end'])
245
-
246
- line = f"{start_time_formatted} --> {end_time_formatted}\n{chunk['text']}"
247
- full_transcript_text.append(line)
248
-
249
-
250
- with open(transcript_filename, "w", encoding="utf-8") as f:
251
- count = 1
252
- for line in full_transcript_text:
253
- f.write(f"{count}\n{line}\n\n")
254
- count += 1
255
-
256
-
257
- end_time = time.time()
258
- processed_time = end_time - start_time
259
-
260
- print(f"\nTranscription complete and saved to {transcript_filename}.")
261
- print(f"Processed in {processed_time:.2f} seconds")
262
-
263
- video_output = Path(final_filepath).resolve()
264
- subtitle_output = Path(transcript_filename).resolve()
265
-
266
- files_to_send = [video_output, subtitle_output]
267
-
268
- with tempfile.NamedTemporaryFile(delete=False, suffix=".zip") as tmp:
269
- with zipfile.ZipFile(tmp, "w", zipfile.ZIP_DEFLATED) as zf:
270
- for f in files_to_send:
271
- zf.write(f, arcname=f.name)
272
- tmp_path = tmp.name
273
-
274
-
275
- return FileResponse(tmp_path, media_type="application/zip", filename="subtitles.zip")
276
-
277
- except Exception as e:
278
- raise HTTPException(status_code=400, detail=str(e))
279
-
280
- finally:
281
- if 'model' in locals():
282
- del model
283
- if 'batched_model' in locals():
284
- del batched_model
285
- print("Model resources released.")
286
- import gc
287
- gc.collect()
288
-
289
- else:
290
- raise HTTPException(status_code=400, detail="Failed to process the file.")
291
-
292
 
 
1
+ from faster_whisper import WhisperModel, BatchedInferencePipeline
2
+ import time
3
+ import os
4
+ import yt_dlp
5
+ import subprocess
6
+ from typing import Optional
7
+ import logging
8
+ from fastapi import FastAPI, File, UploadFile, HTTPException, Form
9
+ from fastapi.responses import FileResponse
10
+ import os, time
11
+ from fastapi.middleware.cors import CORSMiddleware
12
+ from pathlib import Path
13
+ import zipfile
14
+ import tempfile
15
+
16
+
17
+ app = FastAPI()
18
+
19
+ app.add_middleware(
20
+ CORSMiddleware,
21
+ allow_origins=["http://localhost:5173", "http://127.0.0.1:5173"],
22
+ allow_credentials=True,
23
+ allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
24
+ allow_headers=["*"],
25
+ )
26
+
27
+ logging.basicConfig()
28
+ logging.getLogger("faster_whisper").setLevel(logging.DEBUG)
29
+
30
+ def youtube_download_video(VIDEO_URL, DOWNLOAD_DIR, output_template):
31
+ URLS = [VIDEO_URL]
32
+ os.makedirs(DOWNLOAD_DIR, exist_ok=True)
33
+
34
+ ydl_opts = {
35
+ 'outtmpl': output_template,
36
+ 'format': 'bestvideo[height<=1080]+bestaudio/best',
37
+ 'merge_output_format': 'mp4',
38
+ 'verbose': True
39
+ }
40
+
41
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
42
+ try:
43
+ print(f"Downloading from YouTube: {URLS[0]}")
44
+ info = ydl.extract_info(URLS[0], download=True)
45
+ if not info:
46
+ return "Error downloading youtube video"
47
+
48
+ final_filepath = None
49
+ if 'requested_downloads' in info and info['requested_downloads']:
50
+ final_filepath = info['requested_downloads'][0]['filepath']
51
+ elif '_filename' in info:
52
+ final_filepath = info['_filename']
53
+ else:
54
+ print("Warning: yt-dlp did not provide a clear filepath. Attempting to construct.")
55
+ if 'title' in info and 'ext' in info:
56
+ guessed_filename = f"{info['title']}.{info['ext']}"
57
+ guessed_path = os.path.join(DOWNLOAD_DIR, guessed_filename)
58
+ if os.path.exists(guessed_path):
59
+ final_filepath = guessed_path
60
+ else:
61
+ print(f"Could not determine downloaded file path for {URLS[0]}.")
62
+
63
+ except Exception as e:
64
+ print(f"An error occurred during YouTube download: {e}")
65
+ final_filepath = None
66
+ finally:
67
+ return final_filepath
68
+
69
+ def local_audio_file(DOWNLOAD_DIR, AUDIO_FILE):
70
+ try:
71
+ potential_path = os.path.join(DOWNLOAD_DIR, AUDIO_FILE)
72
+ if os.path.exists(potential_path):
73
+ final_filepath = potential_path
74
+ print(f"Using local file: {final_filepath}")
75
+ elif os.path.exists(AUDIO_FILE):
76
+ final_filepath = AUDIO_FILE
77
+ print(f"Using local file: {final_filepath}")
78
+ else:
79
+ print(f"Local file not found at '{potential_path}' or as '{AUDIO_FILE}'")
80
+ final_filepath = None
81
+ except Exception as e:
82
+ final_path = None
83
+ print(f"Error finding file:{e}")
84
+ finally:
85
+ return final_filepath
86
+
87
+ def create_subtitle_chunks(segments, max_words=8, max_duration=5.0):
88
+ subtitle_chunks = []
89
+
90
+ for segment in segments:
91
+ if hasattr(segment, 'words') and segment.words:
92
+ current_chunk = []
93
+ chunk_start = segment.words[0].start
94
+
95
+ for i, word in enumerate(segment.words):
96
+ current_chunk.append(word.word)
97
+
98
+ if (len(current_chunk) >= max_words or
99
+ word.end - chunk_start >= max_duration):
100
+
101
+ text = ''.join(current_chunk).strip()
102
+ subtitle_chunks.append({
103
+ 'start': chunk_start,
104
+ 'end': word.end,
105
+ 'text': text
106
+ })
107
+
108
+ current_chunk = []
109
+ if i + 1 < len(segment.words):
110
+ chunk_start = segment.words[i + 1].start
111
+
112
+ if current_chunk:
113
+ text = ''.join(current_chunk).strip()
114
+ subtitle_chunks.append({
115
+ 'start': chunk_start,
116
+ 'end': segment.words[-1].end,
117
+ 'text': text
118
+ })
119
+ else:
120
+ subtitle_chunks.append({
121
+ 'start': segment.start,
122
+ 'end': segment.end,
123
+ 'text': segment.text
124
+ })
125
+
126
+ return subtitle_chunks
127
+
128
+ def format_time(seconds):
129
+ seconds -= 0.2
130
+ hours = int(seconds // 3600)
131
+ minutes = int((seconds % 3600) // 60)
132
+ seconds_remainder = seconds % 60
133
+ milliseconds = int((seconds_remainder - int(seconds_remainder)) * 1000)
134
+
135
+ return f"{hours:02d}:{minutes:02d}:{int(seconds_remainder):02d},{milliseconds:03d}"
136
+
137
+ def add_subtitles(media_path):
138
+ base, ext = os.path.splitext(os.path.basename(media_path))
139
+ dir_path = os.path.dirname(media_path)
140
+
141
+ final_output = os.path.join(dir_path, f"{base}_subtitled.mp4")
142
+ subtitle_file = os.path.join(dir_path, f"{base}.srt")
143
+
144
+ if not os.path.exists(subtitle_file):
145
+ print(f"Error: Subtitle file not found at {subtitle_file}")
146
+ return
147
+
148
+ video_formats = ['.mp4', '.webm', '.mpeg']
149
+
150
+ try:
151
+ if ext.lower() in video_formats:
152
+ print('Found video file.')
153
+
154
+ temp_output = os.path.join(dir_path, f"{base}_temp.mp4")
155
+ cmd = ['ffmpeg', '-i', media_path, '-i', subtitle_file, '-c', 'copy', '-c:s', 'mov_text', temp_output, '-y']
156
+
157
+ subprocess.run(cmd, check=True, capture_output=True)
158
+
159
+ if ext.lower() == ".mp4":
160
+ os.remove(media_path)
161
+ os.rename(temp_output, media_path)
162
+ else:
163
+ os.rename(temp_output, final_output)
164
+ else:
165
+ print('Found audio file.')
166
+ temp_video = os.path.join(dir_path, f"{base}_temp.mp4")
167
+ cmd1 = ['ffmpeg', '-f', 'lavfi', '-i', 'color=c=black:s=1280x720:r=5',
168
+ '-i', media_path, '-c:a', 'copy', '-shortest', temp_video, '-y']
169
+ subprocess.run(cmd1, check=True, capture_output=True)
170
+
171
+ cmd2 = ['ffmpeg', '-i', temp_video, '-i', subtitle_file, '-c',
172
+ 'copy', '-c:s', 'mov_text', final_output, '-y']
173
+ subprocess.run(cmd2, check=True, capture_output=True)
174
+ os.remove(temp_video)
175
+
176
+ return final_output
177
+
178
+ except subprocess.CalledProcessError as e:
179
+ print(f"FFmpeg Error: {e.stderr.decode()}")
180
+ except Exception as e:
181
+ print(f"An error occurred: {e}")
182
+
183
+ @app.get('/test')
184
+ async def test_endpoint():
185
+ return {"message": "FastAPI is working!"}
186
+
187
+ @app.post('/generate-subtitles')
188
+ async def generate_subtitles(
189
+ file: Optional[UploadFile] = File(None),
190
+ youtube_url: Optional[str] = Form(None)
191
+ ):
192
+
193
+ upload_dir = 'audio'
194
+ os.makedirs(upload_dir, exist_ok=True)
195
+
196
+ if file:
197
+ file_path = os.path.join(upload_dir, file.filename)
198
+ with open(file_path, "wb") as f:
199
+ f.write(await file.read())
200
+ final_filepath = file_path
201
+ print(f"Uploaded file saved to {final_filepath}")
202
+ elif youtube_url:
203
+ output_template = os.path.join(upload_dir, "%(title)s.%(ext)s")
204
+ final_filepath = youtube_download_video(youtube_url, upload_dir, output_template)
205
+ else:
206
+ raise HTTPException(status_code=400, detail="You must provide either a file or youtube URL.")
207
+
208
+
209
+ if final_filepath and os.path.exists(final_filepath):
210
+ print(f"Processing audio file: {final_filepath}")
211
+ print(f"File size: {os.path.getsize(final_filepath) / 1024 / 1024:.2f} MB")
212
+
213
+ base_name = os.path.basename(final_filepath)
214
+ file_name_without_extension, _ = os.path.splitext(base_name)
215
+
216
+ FILE_NAME_FOR_TXT = file_name_without_extension
217
+ MODEL_NAME = "small"
218
+
219
+ print(f"\nLoading Whisper model: {MODEL_NAME}...")
220
+ try:
221
+ model_path = os.path.join('models', 'snapshots', '536b0662742c02347bc0e980a01041f333bce120')
222
+ model = WhisperModel(model_path, device="cpu", compute_type="int8")
223
+ batched_model = BatchedInferencePipeline(model=model)
224
+ print("Model loaded successfully.")
225
+
226
+ print("\nStarting transcription...")
227
+ start_time = time.time()
228
+
229
+ segments, info = batched_model.transcribe(
230
+ final_filepath,
231
+ batch_size=8,
232
+ beam_size=5,
233
+ word_timestamps=True
234
+ )
235
+
236
+ os.makedirs(upload_dir, exist_ok=True)
237
+ transcript_filename = os.path.join(upload_dir, f"{FILE_NAME_FOR_TXT}.srt")
238
+
239
+ subtitle_chunks = create_subtitle_chunks(segments, max_words=12, max_duration=4.0)
240
+
241
+ full_transcript_text = []
242
+ for chunk in subtitle_chunks:
243
+ start_time_formatted = format_time(chunk['start'])
244
+ end_time_formatted = format_time(chunk['end'])
245
+
246
+ line = f"{start_time_formatted} --> {end_time_formatted}\n{chunk['text']}"
247
+ full_transcript_text.append(line)
248
+
249
+
250
+ with open(transcript_filename, "w", encoding="utf-8") as f:
251
+ count = 1
252
+ for line in full_transcript_text:
253
+ f.write(f"{count}\n{line}\n\n")
254
+ count += 1
255
+
256
+
257
+ end_time = time.time()
258
+ processed_time = end_time - start_time
259
+
260
+ print(f"\nTranscription complete and saved to {transcript_filename}.")
261
+ print(f"Processed in {processed_time:.2f} seconds")
262
+
263
+ video_output = Path(final_filepath).resolve()
264
+ subtitle_output = Path(transcript_filename).resolve()
265
+
266
+ files_to_send = [video_output, subtitle_output]
267
+
268
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".zip") as tmp:
269
+ with zipfile.ZipFile(tmp, "w", zipfile.ZIP_DEFLATED) as zf:
270
+ for f in files_to_send:
271
+ zf.write(f, arcname=f.name)
272
+ tmp_path = tmp.name
273
+
274
+
275
+ return FileResponse(tmp_path, media_type="application/zip", filename="subtitles.zip")
276
+
277
+ except Exception as e:
278
+ raise HTTPException(status_code=400, detail=str(e))
279
+
280
+ finally:
281
+ if 'model' in locals():
282
+ del model
283
+ if 'batched_model' in locals():
284
+ del batched_model
285
+ print("Model resources released.")
286
+ import gc
287
+ gc.collect()
288
+
289
+ else:
290
+ raise HTTPException(status_code=400, detail="Failed to process the file.")
291
+
292