uzi007 commited on
Commit
fe9dbf9
1 Parent(s): bc72637

APIs updated & yt-dlp added

Browse files
helperfunctions.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import subprocess
3
+
4
+
5
+ def extract_audio(video_path):
6
+ """
7
+ Extract audio from a video file (MP4 or WebM) and save it as an MP3 file using ffmpeg.
8
+
9
+ Args:
10
+ video_path (str): Path to the input video file.
11
+
12
+ Returns:
13
+ str: Path of extracted audio.
14
+ """
15
+ try:
16
+ # Path for Extracted Audio File
17
+ filename, extension = os.path.splitext(video_path)
18
+ audio_path = filename + '.mp3'
19
+
20
+ # Choosing the Appropriate Codec for the Output Audio Format (MP3)
21
+ audio_codec = "libmp3lame" if extension.lower() in (".mp4", ".webm") else "mp3"
22
+
23
+ # Extracting Audio using FFMPEG Command
24
+ command = ["ffmpeg", "-i", video_path, "-vn", "-acodec",
25
+ audio_codec, audio_path, '-loglevel', 'quiet']
26
+ subprocess.run(command, check=True)
27
+
28
+ return audio_path
29
+
30
+ except Exception as e:
31
+ print(f"Error in extract_audio: {e}")
32
+
33
+ def burn_subtitles(video_file_path, subtitle_file_path):
34
+ '''
35
+ Burns the subtitles onto the video
36
+
37
+ Args:
38
+ video_file_path (str): Path to the input video file.
39
+ subtitle_file_path (str): Path to the subtitle file.
40
+
41
+ Returns:
42
+ str: Path of output video with subtitles.
43
+ '''
44
+ try:
45
+ # Getting Output File Path
46
+ video_filename, video_extension = os.path.splitext(video_file_path)
47
+ subtitle_filename, subtitle_extension = os.path.splitext(subtitle_file_path)
48
+ output_file_path = video_filename + subtitle_extension.replace('.', '_') + video_extension
49
+
50
+ # Burning the Subtitles onto Video using FFMPEG Command
51
+ command = ['ffmpeg', '-i', video_file_path,
52
+ '-vf', f'subtitles={subtitle_file_path}',
53
+ output_file_path, '-loglevel', 'quiet']
54
+ subprocess.run(command, check=True)
55
+
56
+ return output_file_path
57
+
58
+ except Exception as e:
59
+ print(f"Error in burn_subtitles: {e}")
60
+
61
+ def convert_to_srt_time_format(seconds):
62
+ '''
63
+ Converts seconds into .srt format
64
+ '''
65
+
66
+ try:
67
+ hours = seconds // 3600
68
+ seconds %= 3600
69
+ minutes = seconds // 60
70
+ seconds %= 60
71
+ milliseconds = int((seconds - int(seconds)) * 1000)
72
+ return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d},{milliseconds:03d}"
73
+
74
+ except Exception as e:
75
+ print(f"Error in save_translated_subtitles: {e}")
76
+
77
+ def save_translated_subtitles(subtitles, media_path):
78
+ '''
79
+ Saves the translated subtitles into .srt file
80
+ '''
81
+
82
+ try:
83
+ # Converting to SRT Format
84
+ srt_content = ""
85
+ counter = 1
86
+ for subtitle in subtitles:
87
+ start_time = subtitle['start']
88
+ end_time = subtitle['end']
89
+ text = subtitle['text']
90
+
91
+ srt_content += f"{counter}\n"
92
+ srt_content += f"{convert_to_srt_time_format(start_time)} --> {convert_to_srt_time_format(end_time)}\n"
93
+ srt_content += f"{text}\n\n"
94
+
95
+ counter += 1
96
+
97
+ # Saving SRT content to a .srt file
98
+ print(media_path)
99
+ subtitles_filename = os.path.splitext(media_path)[0]
100
+ subtitles_filename = f'{subtitles_filename}.srt'
101
+ print(subtitles_filename)
102
+ with open(subtitles_filename, 'w', encoding='utf-8') as srt_file:
103
+ srt_file.write(srt_content)
104
+
105
+ return subtitles_filename
106
+
107
+ except Exception as e:
108
+ print(f"Error in save_translated_subtitles: {e}")
languages.py ADDED
@@ -0,0 +1,411 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenAI Whisper - Supported Languages
2
+ whisper_languages = [
3
+ 'afrikaans',
4
+ 'arabic',
5
+ 'armenian',
6
+ 'azerbaijani',
7
+ 'belarusian',
8
+ 'bosnian',
9
+ 'bulgarian',
10
+ 'catalan',
11
+ 'chinese',
12
+ 'croatian',
13
+ 'czech',
14
+ 'danish',
15
+ 'dutch',
16
+ 'english',
17
+ 'estonian',
18
+ 'finnish',
19
+ 'french',
20
+ 'galician',
21
+ 'german',
22
+ 'greek',
23
+ 'hebrew',
24
+ 'hindi',
25
+ 'hungarian',
26
+ 'icelandic',
27
+ 'indonesian',
28
+ 'italian',
29
+ 'japanese',
30
+ 'kannada',
31
+ 'kazakh',
32
+ 'korean',
33
+ 'latvian',
34
+ 'lithuanian',
35
+ 'macedonian',
36
+ 'malay',
37
+ 'marathi',
38
+ 'maori',
39
+ 'nepali',
40
+ 'norwegian',
41
+ 'persian',
42
+ 'polish',
43
+ 'portuguese',
44
+ 'romanian',
45
+ 'russian',
46
+ 'serbian',
47
+ 'slovak',
48
+ 'slovenian',
49
+ 'spanish',
50
+ 'swahili',
51
+ 'swedish',
52
+ 'tagalog',
53
+ 'tamil',
54
+ 'thai',
55
+ 'turkish',
56
+ 'ukrainian',
57
+ 'urdu',
58
+ 'vietnamese',
59
+ 'welsh'
60
+ ]
61
+
62
+ # Google Translate - Supported Languages
63
+ gt_languages = {
64
+ 'afrikaans': 'af',
65
+ 'albanian': 'sq',
66
+ 'amharic': 'am',
67
+ 'arabic': 'ar',
68
+ 'armenian': 'hy',
69
+ 'assamese': 'as',
70
+ 'aymara': 'ay',
71
+ 'azerbaijani': 'az',
72
+ 'bambara': 'bm',
73
+ 'basque': 'eu',
74
+ 'belarusian': 'be',
75
+ 'bengali': 'bn',
76
+ 'bhojpuri': 'bho',
77
+ 'bosnian': 'bs',
78
+ 'bulgarian': 'bg',
79
+ 'catalan': 'ca',
80
+ 'cebuano': 'ceb',
81
+ 'chichewa': 'ny',
82
+ 'chinese (simplified)': 'zh-CN',
83
+ 'chinese (traditional)': 'zh-TW',
84
+ 'corsican': 'co',
85
+ 'croatian': 'hr',
86
+ 'czech': 'cs',
87
+ 'danish': 'da',
88
+ 'dhivehi': 'dv',
89
+ 'dogri': 'doi',
90
+ 'dutch': 'nl',
91
+ 'english': 'en',
92
+ 'esperanto': 'eo',
93
+ 'estonian': 'et',
94
+ 'ewe': 'ee',
95
+ 'filipino': 'tl',
96
+ 'finnish': 'fi',
97
+ 'french': 'fr',
98
+ 'frisian': 'fy',
99
+ 'galician': 'gl',
100
+ 'georgian': 'ka',
101
+ 'german': 'de',
102
+ 'greek': 'el',
103
+ 'guarani': 'gn',
104
+ 'gujarati': 'gu',
105
+ 'haitian creole': 'ht',
106
+ 'hausa': 'ha',
107
+ 'hawaiian': 'haw',
108
+ 'hebrew': 'iw',
109
+ 'hindi': 'hi',
110
+ 'hmong': 'hmn',
111
+ 'hungarian': 'hu',
112
+ 'icelandic': 'is',
113
+ 'igbo': 'ig',
114
+ 'ilocano': 'ilo',
115
+ 'indonesian': 'id',
116
+ 'irish': 'ga',
117
+ 'italian': 'it',
118
+ 'japanese': 'ja',
119
+ 'javanese': 'jw',
120
+ 'kannada': 'kn',
121
+ 'kazakh': 'kk',
122
+ 'khmer': 'km',
123
+ 'kinyarwanda': 'rw',
124
+ 'konkani': 'gom',
125
+ 'korean': 'ko',
126
+ 'krio': 'kri',
127
+ 'kurdish (kurmanji)': 'ku',
128
+ 'kurdish (sorani)': 'ckb',
129
+ 'kyrgyz': 'ky',
130
+ 'lao': 'lo',
131
+ 'latin': 'la',
132
+ 'latvian': 'lv',
133
+ 'lingala': 'ln',
134
+ 'lithuanian': 'lt',
135
+ 'luganda': 'lg',
136
+ 'luxembourgish': 'lb',
137
+ 'macedonian': 'mk',
138
+ 'maithili': 'mai',
139
+ 'malagasy': 'mg',
140
+ 'malay': 'ms',
141
+ 'malayalam': 'ml',
142
+ 'maltese': 'mt',
143
+ 'maori': 'mi',
144
+ 'marathi': 'mr',
145
+ 'meiteilon (manipuri)': 'mni-Mtei',
146
+ 'mizo': 'lus',
147
+ 'mongolian': 'mn',
148
+ 'myanmar': 'my',
149
+ 'nepali': 'ne',
150
+ 'norwegian': 'no',
151
+ 'odia (oriya)': 'or',
152
+ 'oromo': 'om',
153
+ 'pashto': 'ps',
154
+ 'persian': 'fa',
155
+ 'polish': 'pl',
156
+ 'portuguese': 'pt',
157
+ 'punjabi': 'pa',
158
+ 'quechua': 'qu',
159
+ 'romanian': 'ro',
160
+ 'russian': 'ru',
161
+ 'samoan': 'sm',
162
+ 'sanskrit': 'sa',
163
+ 'scots gaelic': 'gd',
164
+ 'sepedi': 'nso',
165
+ 'serbian': 'sr',
166
+ 'sesotho': 'st',
167
+ 'shona': 'sn',
168
+ 'sindhi': 'sd',
169
+ 'sinhala': 'si',
170
+ 'slovak': 'sk',
171
+ 'slovenian': 'sl',
172
+ 'somali': 'so',
173
+ 'spanish': 'es',
174
+ 'sundanese': 'su',
175
+ 'swahili': 'sw',
176
+ 'swedish': 'sv',
177
+ 'tajik': 'tg',
178
+ 'tamil': 'ta',
179
+ 'tatar': 'tt',
180
+ 'telugu': 'te',
181
+ 'thai': 'th',
182
+ 'tigrinya': 'ti',
183
+ 'tsonga': 'ts',
184
+ 'turkish': 'tr',
185
+ 'turkmen': 'tk',
186
+ 'twi': 'ak',
187
+ 'ukrainian': 'uk',
188
+ 'urdu': 'ur',
189
+ 'uyghur': 'ug',
190
+ 'uzbek': 'uz',
191
+ 'vietnamese': 'vi',
192
+ 'welsh': 'cy',
193
+ 'xhosa': 'xh',
194
+ 'yiddish': 'yi',
195
+ 'yoruba': 'yo',
196
+ 'zulu': 'zu'
197
+ }
198
+
199
+ # NLLB - Supported Languages
200
+ nllb_languages = [
201
+ 'Acehnese (Arabic script)',
202
+ 'Acehnese (Latin script)',
203
+ 'Afrikaans',
204
+ 'Akan',
205
+ 'Amharic',
206
+ 'Armenian',
207
+ 'Assamese',
208
+ 'Asturian',
209
+ 'Awadhi',
210
+ 'Ayacucho Quechua',
211
+ 'Balinese',
212
+ 'Bambara',
213
+ 'Banjar (Arabic script)',
214
+ 'Banjar (Latin script)',
215
+ 'Bashkir',
216
+ 'Basque',
217
+ 'Belarusian',
218
+ 'Bemba',
219
+ 'Bengali',
220
+ 'Bhojpuri',
221
+ 'Bosnian',
222
+ 'Buginese',
223
+ 'Bulgarian',
224
+ 'Burmese',
225
+ 'Catalan',
226
+ 'Cebuano',
227
+ 'Central Atlas Tamazight',
228
+ 'Central Aymara',
229
+ 'Central Kanuri (Arabic script)',
230
+ 'Central Kanuri (Latin script)',
231
+ 'Central Kurdish',
232
+ 'Chhattisgarhi',
233
+ 'Chinese (Simplified)',
234
+ 'Chinese (Traditional)',
235
+ 'Chokwe',
236
+ 'Crimean Tatar',
237
+ 'Croatian',
238
+ 'Czech',
239
+ 'Danish',
240
+ 'Dari',
241
+ 'Dutch',
242
+ 'Dyula',
243
+ 'Dzongkha',
244
+ 'Eastern Panjabi',
245
+ 'Eastern Yiddish',
246
+ 'Egyptian Arabic',
247
+ 'English',
248
+ 'Esperanto',
249
+ 'Estonian',
250
+ 'Ewe',
251
+ 'Faroese',
252
+ 'Fijian',
253
+ 'Finnish',
254
+ 'Fon',
255
+ 'French',
256
+ 'Friulian',
257
+ 'Galician',
258
+ 'Ganda',
259
+ 'Georgian',
260
+ 'German',
261
+ 'Greek',
262
+ 'Guarani',
263
+ 'Gujarati',
264
+ 'Haitian Creole',
265
+ 'Halh Mongolian',
266
+ 'Hausa',
267
+ 'Hebrew',
268
+ 'Hindi',
269
+ 'Hungarian',
270
+ 'Icelandic',
271
+ 'Igbo',
272
+ 'Ilocano',
273
+ 'Indonesian',
274
+ 'Irish',
275
+ 'Italian',
276
+ 'Japanese',
277
+ 'Javanese',
278
+ 'Jingpho',
279
+ 'Kabiyè',
280
+ 'Kabuverdianu',
281
+ 'Kabyle',
282
+ 'Kamba',
283
+ 'Kannada',
284
+ 'Kashmiri (Arabic script)',
285
+ 'Kashmiri (Devanagari script)',
286
+ 'Kazakh',
287
+ 'Khmer',
288
+ 'Kikongo',
289
+ 'Kikuyu',
290
+ 'Kimbundu',
291
+ 'Kinyarwanda',
292
+ 'Korean',
293
+ 'Kyrgyz',
294
+ 'Lao',
295
+ 'Latgalian',
296
+ 'Ligurian',
297
+ 'Limburgish',
298
+ 'Lingala',
299
+ 'Lithuanian',
300
+ 'Lombard',
301
+ 'Luba-Kasai',
302
+ 'Luo',
303
+ 'Luxembourgish',
304
+ 'Macedonian',
305
+ 'Magahi',
306
+ 'Maithili',
307
+ 'Malayalam',
308
+ 'Maltese',
309
+ 'Maori',
310
+ 'Marathi',
311
+ 'Meitei (Bengali script)',
312
+ 'Mesopotamian Arabic',
313
+ 'Minangkabau (Arabic script)',
314
+ 'Minangkabau (Latin script)',
315
+ 'Mizo',
316
+ 'Modern Standard Arabic',
317
+ 'Modern Standard Arabic (Romanized)',
318
+ 'Moroccan Arabic',
319
+ 'Mossi',
320
+ 'Najdi Arabic',
321
+ 'Nepali',
322
+ 'Nigerian Fulfulde',
323
+ 'North Azerbaijani',
324
+ 'North Levantine Arabic',
325
+ 'Northern Kurdish',
326
+ 'Northern Sotho',
327
+ 'Northern Uzbek',
328
+ 'Norwegian Bokmål',
329
+ 'Norwegian Nynorsk',
330
+ 'Nuer',
331
+ 'Nyanja',
332
+ 'Occitan',
333
+ 'Odia',
334
+ 'Pangasinan',
335
+ 'Papiamento',
336
+ 'Plateau Malagasy',
337
+ 'Polish',
338
+ 'Portuguese',
339
+ 'Romanian',
340
+ 'Rundi',
341
+ 'Russian',
342
+ 'Samoan',
343
+ 'Sango',
344
+ 'Sanskrit',
345
+ 'Santali',
346
+ 'Sardinian',
347
+ 'Scottish Gaelic',
348
+ 'Serbian',
349
+ 'Shan',
350
+ 'Shona',
351
+ 'Sicilian',
352
+ 'Silesian',
353
+ 'Sindhi',
354
+ 'Sinhala',
355
+ 'Slovak',
356
+ 'Slovenian',
357
+ 'Somali',
358
+ 'South Azerbaijani',
359
+ 'South Levantine Arabic',
360
+ 'Southern Pashto',
361
+ 'Southern Sotho',
362
+ 'Southwestern Dinka',
363
+ 'Spanish',
364
+ 'Standard Latvian',
365
+ 'Standard Malay',
366
+ 'Standard Tibetan',
367
+ 'Sundanese',
368
+ 'Swahili',
369
+ 'Swati',
370
+ 'Swedish',
371
+ "Ta'izzi-Adeni Arabic",
372
+ 'Tagalog',
373
+ 'Tajik',
374
+ 'Tamasheq (Latin script)',
375
+ 'Tamasheq (Tifinagh script)',
376
+ 'Tamil',
377
+ 'Tatar',
378
+ 'Telugu',
379
+ 'Thai',
380
+ 'Tigrinya',
381
+ 'Tok Pisin',
382
+ 'Tosk Albanian',
383
+ 'Tsonga',
384
+ 'Tswana',
385
+ 'Tumbuka',
386
+ 'Tunisian Arabic',
387
+ 'Turkish',
388
+ 'Turkmen',
389
+ 'Twi',
390
+ 'Ukrainian',
391
+ 'Umbundu',
392
+ 'Urdu',
393
+ 'Uyghur',
394
+ 'Venetian',
395
+ 'Vietnamese',
396
+ 'Waray',
397
+ 'Welsh',
398
+ 'West Central Oromo',
399
+ 'Western Persian',
400
+ 'Wolof',
401
+ 'Xhosa',
402
+ 'Yoruba',
403
+ 'Yue Chinese',
404
+ 'Zulu'
405
+ ]
406
+
407
+ LANGUAGES = {}
408
+ for lang in nllb_languages:
409
+ lang_code = gt_languages.get(lang.lower(), None)
410
+ if lang_code:
411
+ LANGUAGES[lang_code] = lang
main.py CHANGED
@@ -8,9 +8,10 @@ from fastapi import FastAPI, Request
8
  from fastapi.middleware.cors import CORSMiddleware
9
 
10
  from media_download import YoutubeDownloader
11
- from transcription import StableWhisper
12
- from summarizer import Extract_Summary, AudioBookNarration
13
- from audiobook import AudioBook
 
14
 
15
 
16
  ### API Configurations
@@ -23,25 +24,25 @@ output_folder = 'Output'
23
  # Create a context variable to store the contexts for each user
24
  users_context = dict()
25
 
26
- # CORS (Cross-Origin Resource Sharing)
27
- origins = [
28
- "http://localhost",
29
- "http://localhost:4200",
30
- ]
31
 
32
- app.add_middleware(
33
- CORSMiddleware,
34
- allow_origins=["*"], # origins,
35
- allow_credentials=True,
36
- allow_methods=["*"],
37
- allow_headers=["*"],
38
- )
39
 
40
 
41
  ### APIs
42
 
43
- @app.get("/get_media_info")
44
- async def get_media_info(request: Request, url: str):
45
 
46
  # Getting User's IP
47
  # user_ip = request.client.host
@@ -51,15 +52,39 @@ async def get_media_info(request: Request, url: str):
51
  youtube_downloader = YoutubeDownloader(url, output_folder)
52
 
53
  # Getting Youtube Media Info
54
- media_info = youtube_downloader.get_media_info()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- # Storing Info in the context for this user's session
57
- users_context[user_ip] = dict()
58
- users_context[user_ip]['downloader'] = youtube_downloader
59
- # users_context[user_ip]['media_info'] = media_info
60
- users_context[user_ip]['url'] = url
 
61
 
62
- return media_info
63
 
64
 
65
  @app.get("/download_media")
@@ -80,11 +105,11 @@ async def download_media(request: Request, media_type: str, media_format: str, m
80
  users_context[user_ip]['media_path'] = media_path
81
  users_context[user_ip]['media_type'] = media_type
82
 
83
- return {"status": status}
84
 
85
 
86
  @app.get("/get_transcript")
87
- async def get_transcript(request: Request, subtitle_format: str = 'srt', word_level: bool = True):
88
 
89
  # Getting User's IP
90
  # user_ip = request.client.host
@@ -96,7 +121,7 @@ async def get_transcript(request: Request, subtitle_format: str = 'srt', word_le
96
  # Checking if the media_type is Video, then extract it's audio
97
  media_type = users_context[user_ip]['media_type']
98
  if media_type == 'video':
99
- media_path = users_context[user_ip]['downloader'].extract_audio(media_path)
100
 
101
  # # Whisper based transcription
102
  # stable_whisper_transcript = StableWhisper(media_path, output_folder, subtitle_format=subtitle_format, word_level=word_level)
@@ -122,7 +147,44 @@ async def get_transcript(request: Request, subtitle_format: str = 'srt', word_le
122
  users_context[user_ip]['transcript'] = transcript
123
  users_context[user_ip]['transcript_path'] = transcript_path
124
 
125
- return {"status": status, "transcript": transcript}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
 
128
  @app.get("/get_summary")
@@ -159,7 +221,7 @@ async def get_summary(request: Request, Summary_type: str, Summary_strategy: str
159
  # Storing Summary Info in the context for this user's session
160
  users_context[user_ip]['summary'] = output
161
 
162
- return {"status": status, "summary": output}
163
 
164
 
165
  @app.get("/get_key_info")
@@ -196,11 +258,11 @@ async def get_key_info(request: Request, Summary_type: str, Summary_strategy: st
196
  # Storing Key Info in the context for this user's session
197
  users_context[user_ip]['key_info'] = output
198
 
199
- return {"status": status, "key_info": output}
200
 
201
 
202
  # @app.get("/get_narration")
203
- # async def get_narration(request: Request, Narration_style: str, text_input: str = None):
204
 
205
  # # Getting User's IP
206
  # # user_ip = request.client.host
@@ -212,7 +274,7 @@ async def get_key_info(request: Request, Summary_type: str, Summary_strategy: st
212
 
213
  # # # Extracting Narration
214
  # # narrator = AudioBookNarration(text_input=text_input)
215
- # # output = narrator.define_chain(Narration_style=Narration_style)
216
 
217
  # temp_dir = 'temp'
218
  # file_path = os.path.join(temp_dir, 'narration.txt')
@@ -227,11 +289,11 @@ async def get_key_info(request: Request, Summary_type: str, Summary_strategy: st
227
  # # Storing Narration Info in the context for this user's session
228
  # users_context[user_ip]['narration'] = output
229
 
230
- # return {"status": status, "narration": output}
231
 
232
 
233
- @app.get("/get_naration_and_audiobook")
234
- async def get_audiobook(request: Request,Narration_style: str, output_type : str ,speaker: str = "male", text_input: str = None,):
235
 
236
  # Getting User's IP
237
  # user_ip = request.client.host
@@ -244,7 +306,7 @@ async def get_audiobook(request: Request,Narration_style: str, output_type : str
244
  # # Extracting Narration
245
 
246
  # narrator = AudioBookNarration(text_input=text_input)
247
- # output = narrator.define_chain(Narration_style=Narration_style)
248
 
249
  # # Generating Audiobook
250
  # audiobook = AudioBook(output_folder=output_folder)
@@ -262,7 +324,39 @@ async def get_audiobook(request: Request,Narration_style: str, output_type : str
262
  # Storing Audiobook path in the context for this user's session
263
  users_context[user_ip]['audiobook_path'] = audio_path
264
 
265
- return {"status": status, "audiobook_path": audio_path}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
 
268
  if __name__ == "__main__":
 
8
  from fastapi.middleware.cors import CORSMiddleware
9
 
10
  from media_download import YoutubeDownloader
11
+ # from transcription import StableWhisper
12
+ # from summarizer import Extract_Summary, AudioBookNarration
13
+ # from audiobook import AudioBook
14
+ from helperfunctions import *
15
 
16
 
17
  ### API Configurations
 
24
  # Create a context variable to store the contexts for each user
25
  users_context = dict()
26
 
27
+ # # CORS (Cross-Origin Resource Sharing)
28
+ # origins = [
29
+ # "http://localhost",
30
+ # "http://localhost:4200",
31
+ # ]
32
 
33
+ # app.add_middleware(
34
+ # CORSMiddleware,
35
+ # allow_origins=["*"], # origins,
36
+ # allow_credentials=True,
37
+ # allow_methods=["*"],
38
+ # allow_headers=["*"],
39
+ # )
40
 
41
 
42
  ### APIs
43
 
44
+ @app.get("/get_media_metadata")
45
+ async def get_media_metadata(request: Request, url: str):
46
 
47
  # Getting User's IP
48
  # user_ip = request.client.host
 
52
  youtube_downloader = YoutubeDownloader(url, output_folder)
53
 
54
  # Getting Youtube Media Info
55
+ media_metadata = youtube_downloader.get_media_metadata()
56
+
57
+ # Getting Status
58
+ status = 1 if media_metadata else 0
59
+
60
+ if status:
61
+ # Storing Info in the context for this user's session
62
+ users_context[user_ip] = dict()
63
+ users_context[user_ip]['downloader'] = youtube_downloader
64
+ # users_context[user_ip]['media_metadata'] = media_metadata
65
+ users_context[user_ip]['url'] = url
66
+
67
+ return {'status': status, 'media_metadata': media_metadata}
68
+
69
+
70
+ @app.get("/get_media_formats")
71
+ async def get_media_formats(request: Request):
72
+
73
+ # Getting User's IP
74
+ # user_ip = request.client.host
75
+ user_ip = 1
76
+
77
+ # Downloading Media for User
78
+ media_formats = users_context[user_ip]['downloader'].get_media_formats()
79
 
80
+ # Getting Status
81
+ status = 1 if media_formats else 0
82
+
83
+ if status:
84
+ # Storing Media Info in the context for this user's session
85
+ users_context[user_ip]['media_formats'] = media_formats
86
 
87
+ return {'status': status, 'media_formats': media_formats}
88
 
89
 
90
  @app.get("/download_media")
 
105
  users_context[user_ip]['media_path'] = media_path
106
  users_context[user_ip]['media_type'] = media_type
107
 
108
+ return {'status': status, 'media_path': media_path}
109
 
110
 
111
  @app.get("/get_transcript")
112
+ async def get_transcript(request: Request, subtitle_format: str = 'srt', word_level: bool = False):
113
 
114
  # Getting User's IP
115
  # user_ip = request.client.host
 
121
  # Checking if the media_type is Video, then extract it's audio
122
  media_type = users_context[user_ip]['media_type']
123
  if media_type == 'video':
124
+ media_path = extract_audio(media_path)
125
 
126
  # # Whisper based transcription
127
  # stable_whisper_transcript = StableWhisper(media_path, output_folder, subtitle_format=subtitle_format, word_level=word_level)
 
147
  users_context[user_ip]['transcript'] = transcript
148
  users_context[user_ip]['transcript_path'] = transcript_path
149
 
150
+ return {'status': status, "transcript": transcript}
151
+
152
+
153
+ @app.get("/get_translation")
154
+ async def get_translation(request: Request, target_language: str = 'en'):
155
+
156
+ # Getting User's IP
157
+ # user_ip = request.client.host
158
+ user_ip = 1
159
+
160
+ # Retrieving the transcript from the context for this user's session
161
+ transcript = users_context[user_ip]['transcript']
162
+
163
+ # # # NLLB based Translation
164
+ # nllb_translator = Translation(transcript, transcript['language'], target_language, 'output_path')
165
+ # translated_transcript = nllb_translator.get_translated_transcript()
166
+ # translated_subtitles = nllb_translator.get_translated_subtitles()
167
+
168
+ temp_dir = 'temp'
169
+
170
+ translated_transcript_path = os.path.join(temp_dir, 'translated_transcript.txt')
171
+ with open(translated_transcript_path, "r", encoding="utf-8") as f:
172
+ translated_transcript = f.read()
173
+
174
+ translated_subtitles_path = os.path.join(temp_dir, 'translated_subtitles.json')
175
+ with open(translated_subtitles_path, "r", encoding="utf-8") as json_file:
176
+ translated_subtitles = json.load(json_file)
177
+
178
+ # Getting Status
179
+ status = 1 if translated_transcript and translated_subtitles else 0
180
+
181
+ if status:
182
+ # Storing Translated Transcript Info in the context for this user's session
183
+ users_context[user_ip]['translated_transcript'] = translated_transcript
184
+ users_context[user_ip]['translated_subtitles'] = translated_subtitles
185
+ # users_context[user_ip]['transcript_path'] = transcript_path
186
+
187
+ return {'status': status, "transcript": translated_transcript, "subtitles": translated_subtitles}
188
 
189
 
190
  @app.get("/get_summary")
 
221
  # Storing Summary Info in the context for this user's session
222
  users_context[user_ip]['summary'] = output
223
 
224
+ return {'status': status, "summary": output}
225
 
226
 
227
  @app.get("/get_key_info")
 
258
  # Storing Key Info in the context for this user's session
259
  users_context[user_ip]['key_info'] = output
260
 
261
+ return {'status': status, "key_info": output}
262
 
263
 
264
  # @app.get("/get_narration")
265
+ # async def get_narration(request: Request, narration_style: str, text_input: str = None):
266
 
267
  # # Getting User's IP
268
  # # user_ip = request.client.host
 
274
 
275
  # # # Extracting Narration
276
  # # narrator = AudioBookNarration(text_input=text_input)
277
+ # # output = narrator.define_chain(narration_style=narration_style)
278
 
279
  # temp_dir = 'temp'
280
  # file_path = os.path.join(temp_dir, 'narration.txt')
 
289
  # # Storing Narration Info in the context for this user's session
290
  # users_context[user_ip]['narration'] = output
291
 
292
+ # return {'status': status, "narration": output}
293
 
294
 
295
+ @app.get("/get_audiobook")
296
+ async def get_audiobook(request: Request, output_type : str, narration_style: str, speaker: str = "male", text_input: str = None):
297
 
298
  # Getting User's IP
299
  # user_ip = request.client.host
 
306
  # # Extracting Narration
307
 
308
  # narrator = AudioBookNarration(text_input=text_input)
309
+ # output = narrator.define_chain(narration_style=narration_style)
310
 
311
  # # Generating Audiobook
312
  # audiobook = AudioBook(output_folder=output_folder)
 
324
  # Storing Audiobook path in the context for this user's session
325
  users_context[user_ip]['audiobook_path'] = audio_path
326
 
327
+ return {'status': status, "audiobook_path": audio_path}
328
+
329
+
330
+ @app.get("/get_rendered_video")
331
+ async def get_rendered_video(request: Request, subtitles_type: str = 'original'):
332
+
333
+ # Getting User's IP
334
+ # user_ip = request.client.host
335
+ user_ip = 1
336
+
337
+ # Retrieving the media_path from the context for this user's session
338
+ media_path = users_context[user_ip]['media_path']
339
+
340
+ # Getting Required Subtitles
341
+ if subtitles_type == 'original':
342
+ subtitles_path = users_context[user_ip]['transcript_path']
343
+
344
+ elif subtitles_type == 'translated':
345
+
346
+ # Getting Translated Subtitles from the context for this user's session
347
+ translated_subtitles = users_context[user_ip]['translated_subtitles']
348
+
349
+ # Saving Translated Subtitles
350
+ subtitles_path = save_translated_subtitles(translated_subtitles, media_path)
351
+
352
+ # Burning Subtitles & Rendering Video
353
+ rendered_video_path = burn_subtitles(media_path, subtitles_path)
354
+
355
+ # Getting Status
356
+ status = 1 if rendered_video_path else 0
357
+
358
+ return {'status': status, "rendered_video_path": rendered_video_path}
359
+
360
 
361
 
362
  if __name__ == "__main__":
media_download.py CHANGED
@@ -71,8 +71,26 @@ class YoutubeDownloader(MediaDownloader):
71
  self.thumbnail_url = self.youtube.thumbnail_url
72
  self.streams = self.youtube.streams
73
  self.streams_df, self.media_formats_dict = self._get_supported_media_formats()
74
-
75
- def __get_quality_int(self, media_quality):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  '''
77
  Returns the Quality in Integer
78
  E.g: Given input 1080p, it returns 1080
@@ -87,43 +105,97 @@ class YoutubeDownloader(MediaDownloader):
87
  '''
88
  Returns all supported media formats for both audio & video
89
  '''
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
- # Creating Pandas Dataframe for Video Streams' Details
92
- streams_details = []
93
- for stream in self.streams.filter(only_video=True):
94
- media_type = stream.type
95
- media_format = stream.mime_type.split('/')[1]
96
- quality = stream.resolution
97
- progressive = stream.is_progressive
98
- stream_details = [media_type, media_format, quality, progressive]
99
- streams_details.append(stream_details)
100
- cols = ['media_type', 'media_format', 'media_quality', 'progressive']
101
- streams_df = pd.DataFrame(streams_details, columns=cols)
102
-
103
- # Adding Custom Audio Streams
104
- streams_df.loc[len(streams_df)] = ['audio', 'mp3', '128kbps', False]
105
- streams_df.loc[len(streams_df)] = ['audio', 'mp3', '256kbps', False]
106
- streams_df.loc[len(streams_df)] = ['audio', 'wav', '1411kbps', False]
107
-
108
- # Converting to Dictionary for Unique User Options
109
- media_formats_dict = dict()
110
- for media_type in sorted(streams_df['media_type'].unique()):
111
- media_formats_dict[media_type] = dict()
112
- media_type_df = streams_df[streams_df['media_type'] == media_type]
113
- for media_format in sorted(media_type_df['media_format'].unique()):
114
- media_format_df = media_type_df[media_type_df['media_format'] == media_format]
115
- media_qualities = sorted(media_format_df['media_quality'].unique(), key=self.__get_quality_int)
116
- media_formats_dict[media_type][media_format] = media_qualities
117
-
118
- return streams_df, media_formats_dict
119
-
120
- def get_media_formats(self):
121
- '''
122
- Returns a dictioary for supported media formats
123
- '''
124
- return self.media_formats_dict
125
-
126
- def _select_media_format(self):
127
  '''
128
  For selecting media format to download
129
  '''
@@ -186,71 +258,164 @@ class YoutubeDownloader(MediaDownloader):
186
 
187
  return output_path
188
 
189
-
190
  def _download_audio(self, audio_format, audio_quality):
191
  '''
192
  Filters the required audio stream & downloads it
193
  '''
 
 
 
 
194
 
195
- # Getting Quality Command String
196
- quality = str(self.__get_quality_int(audio_quality)) + 'K'
197
-
198
- # Getting Output Path
199
- output_path = os.path.join(self.output_path, f"{self.title}.{audio_format}")
200
 
201
- # Download Command
202
- command = [
203
- "yt-dlp",
204
- "-x", "--audio-format", audio_format,
205
- "--audio-quality", quality,
206
- "-o", output_path,
207
- self.url, "-q"
208
- ]
209
 
210
- # Running the command using Subprocess
211
- subprocess.run(command)
212
 
213
- return output_path
 
 
 
214
 
215
  def _download_video(self, video_format, video_quality):
216
  '''
217
  Filters the required video stream & downloads it
218
  Only for Progressive media i.e containing both audio & video streams
219
  '''
220
- stream = self.streams.filter(progressive=True, file_extension=video_format, resolution=video_quality).first()
221
- print(stream)
222
- video_path = stream.download(output_path=self.output_path, filename=f"{self.title}.{video_format}")
223
- return video_path
224
 
225
- def _download_audio_and_video(self, media_format, media_quality):
226
- '''
227
- Filters the required video stream & downloads it
228
- Filters the best quality audio stream of the same format & downloads it
229
- '''
 
 
 
 
 
 
 
 
230
 
231
- # Downloading Audio
232
- stream = self.streams.filter(file_extension=media_format, only_audio=True).order_by('abr').desc().first()
233
- print(stream)
234
- audio_filename = f"{self.title} - Audio.{media_format}"
235
- audio_path = stream.download(output_path=self.output_path, filename=audio_filename)
236
 
237
- # Downloading Video
238
- stream = self.streams.filter(file_extension=media_format, resolution=media_quality).first()
239
- print(stream)
240
- video_filename = f"{self.title} - Video.{media_format}"
241
- video_path = stream.download(output_path=self.output_path, filename=video_filename)
242
 
243
- # Combining the Audio & Video Files using FFMPEG Command
244
- output_path = os.path.join(self.output_path, f"{self.title}.{media_format}")
245
- command = ['ffmpeg', '-i', video_path, '-i', audio_path,
246
- '-c:v', 'copy', '-c:a', 'copy', output_path,
247
- '-loglevel', 'quiet']
248
- subprocess.run(command)
249
 
250
- os.remove(audio_path)
251
- os.remove(video_path)
 
252
 
253
- return output_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
  def _download_media_chunk(self, media_type, media_format, media_quality):
256
  '''
@@ -270,153 +435,95 @@ class YoutubeDownloader(MediaDownloader):
270
  '''
271
  Filters the required audio stream & downloads it for particular chunk
272
  '''
 
 
 
 
 
273
 
274
- # Getting Chunk Command String
275
- if (self.start_time) and (self.end_time):
276
- chunk_string = f"-ss {self.start_time} -to {self.end_time}"
277
-
278
- elif (self.start_time) and (not self.end_time):
279
- chunk_string = f"-ss {self.start_time}"
280
 
281
- elif (not self.start_time) and (self.end_time):
282
- chunk_string = f"-to {self.end_time}"
283
 
284
- # Getting Quality Command String
285
- quality = str(self.__get_quality_int(audio_quality)) + 'K'
286
 
287
- # Getting Output Path
288
- output_path = os.path.join(self.output_path, f"{self.title}.{audio_format}")
289
 
290
- # Download Command
291
- command = [
292
- "yt-dlp",
293
- "-x", "--audio-format", audio_format,
294
- "--audio-quality", quality,
295
- "--external-downloader", "ffmpeg",
296
- "--external-downloader-args", chunk_string,
297
- "-o", output_path,
298
- url, "-q"
299
- ]
300
 
301
- # Running the command using Subprocess
302
- subprocess.run(command)
303
 
304
- return output_path
 
 
 
305
 
306
  def _download_video_chunk(self, video_format, video_quality):
307
  '''
308
  Filters the required video stream & downloads it for particular chunk
309
  '''
310
 
311
- # Getting Chunk Command String
312
- if (self.start_time) and (self.end_time):
313
- chunk_string = f"-ss {self.start_time} -to {self.end_time}"
314
-
315
- elif (self.start_time) and (not self.end_time):
316
- chunk_string = f"-ss {self.start_time}"
317
-
318
- elif (not self.start_time) and (self.end_time):
319
- chunk_string = f"-to {self.end_time}"
320
-
321
- # Getting Output Path
322
- output_path = os.path.join(self.output_path, f"{self.title}.{video_format}")
323
-
324
- # Getting Video Quality Integer
325
- video_quality = self.__get_quality_int(video_quality)
326
-
327
- # Download Command
328
- if video_format == 'mp4':
329
- video_codec = "h264"
330
- audio_codec = "m4a"
331
-
332
- elif video_format == 'webm':
333
- video_codec = "vp9"
334
- audio_codec = "opus"
335
-
336
- else:
337
- print('Unexpected Video Format Encountered:', video_format)
338
- os.exit(0)
339
-
340
- command = [
341
- "yt-dlp",
342
- url,
343
- "-S", f"res:{video_quality},vcodec:{video_codec},acodec:{audio_codec}",
344
- "--merge-output-format", video_format,
345
- "--download-sections", f"*{self.start_time}-{self.end_time}",
346
- "-o", f"{output_path}",
347
- # "-q"
348
- ]
349
-
350
- print(' '.join(command))
351
 
352
- # Running the command using Subprocess
353
- subprocess.run(command)
354
 
355
- return output_path
 
356
 
357
- def get_media_info(self):
358
- media_info = {
359
- 'title': self.title,
360
- 'media_length': self.media_length,
361
- 'thumbnail_url': self.thumbnail_url,
362
- 'formats': self.media_formats_dict
363
- }
364
- return media_info
365
-
366
- @staticmethod
367
- def extract_audio(video_path):
368
- """
369
- Extract audio from a video file (MP4 or WebM) and save it as an MP3 file using ffmpeg.
370
 
371
- Args:
372
- video_path (str): Path to the input video file.
373
 
374
- Returns:
375
- str: Path of extracted audio.
376
- """
377
- try:
378
- # Path for Extracted Audio File
379
- filename, extension = os.path.splitext(video_path)
380
- audio_path = filename + '.mp3'
381
 
382
- # Choosing the Appropriate Codec for the Output Audio Format (MP3)
383
- audio_codec = "libmp3lame" if extension.lower() in (".mp4", ".webm") else "mp3"
 
384
 
385
- # Extracting Audio using FFMPEG Command
386
- command = ["ffmpeg", "-i", video_path, "-vn", "-acodec",
387
- audio_codec, audio_path, '-loglevel', 'quiet']
388
- subprocess.run(command, check=True)
389
-
390
- return audio_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
 
392
- except subprocess.CalledProcessError as e:
393
- print(f"Error: {e}")
394
-
395
- @staticmethod
396
- def burn_subtitles(video_file_path, subtitle_file_path):
397
- '''
398
- Burns the subtitles onto the video
399
-
400
- Args:
401
- video_file_path (str): Path to the input video file.
402
- subtitle_file_path (str): Path to the subtitle file.
403
-
404
- Returns:
405
- str: Path of output video with subtitles.
406
- '''
407
- try:
408
- # Getting Output File Path
409
- video_filename, video_extension = os.path.splitext(video_file_path)
410
- subtitle_filename, subtitle_extension = os.path.splitext(subtitle_file_path)
411
- output_file_path = video_filename + subtitle_extension.replace('.', '_') + video_extension
412
-
413
- # Burning the Subtitles onto Video using FFMPEG Command
414
- command = ['ffmpeg', '-i', video_file_path,
415
- '-vf', f'subtitles={subtitle_file_path}',
416
- output_file_path, '-loglevel', 'quiet']
417
- subprocess.run(command, check=True)
418
-
419
- return output_file_path
420
-
421
- except subprocess.CalledProcessError as e:
422
- print(f"Error: {e}")
 
71
  self.thumbnail_url = self.youtube.thumbnail_url
72
  self.streams = self.youtube.streams
73
  self.streams_df, self.media_formats_dict = self._get_supported_media_formats()
74
+
75
+ def get_media_formats(self):
76
+ '''
77
+ Returns a dictionary for supported media formats
78
+ '''
79
+ return self.media_formats_dict
80
+
81
+ def get_media_metadata(self):
82
+ '''
83
+ Returns a dictionary for media metadata
84
+ '''
85
+ media_info = {
86
+ 'title': self.title,
87
+ 'media_length': self.media_length,
88
+ 'thumbnail_url': self.thumbnail_url
89
+ }
90
+ return media_info
91
+
92
+ @staticmethod
93
+ def __get_quality_int(media_quality):
94
  '''
95
  Returns the Quality in Integer
96
  E.g: Given input 1080p, it returns 1080
 
105
  '''
106
  Returns all supported media formats for both audio & video
107
  '''
108
+
109
+ try:
110
+ # Creating Pandas Dataframe for Video Streams' Details
111
+ streams_details = []
112
+ for stream in self.streams.filter(only_video=True):
113
+ media_type = stream.type
114
+ media_format = stream.mime_type.split('/')[1]
115
+ quality = stream.resolution
116
+ progressive = stream.is_progressive
117
+ stream_details = [media_type, media_format, quality, progressive]
118
+ streams_details.append(stream_details)
119
+ cols = ['media_type', 'media_format', 'media_quality', 'progressive']
120
+ streams_df = pd.DataFrame(streams_details, columns=cols)
121
+
122
+ # Adding Custom Audio Streams
123
+ streams_df.loc[len(streams_df)] = ['audio', 'mp3', '128kbps', False]
124
+ streams_df.loc[len(streams_df)] = ['audio', 'mp3', '256kbps', False]
125
+ streams_df.loc[len(streams_df)] = ['audio', 'wav', '1411kbps', False]
126
+
127
+ # Converting to Dictionary for Unique User Options
128
+ media_formats_dict = dict()
129
+ for media_type in sorted(streams_df['media_type'].unique()):
130
+ media_formats_dict[media_type] = dict()
131
+ media_type_df = streams_df[streams_df['media_type'] == media_type]
132
+ for media_format in sorted(media_type_df['media_format'].unique()):
133
+ media_format_df = media_type_df[media_type_df['media_format'] == media_format]
134
+ media_qualities = sorted(media_format_df['media_quality'].unique(), key=self.__get_quality_int)
135
+ media_formats_dict[media_type][media_format] = media_qualities
136
+
137
+ return streams_df, media_formats_dict
138
+
139
+ except Exception as pytube_error:
140
+ print(f"PyTube Error in _get_supported_media_formats: \n{pytube_error}\n")
141
+ print('Trying with yt-dlp...')
142
+
143
+ try:
144
+ # Download Command
145
+ command = ["yt-dlp", "--list-formats", url,
146
+ "--get-filename", "--format", "best[ext=mp4]/best[ext=webm]"]
147
+ print(' '.join(command))
148
+
149
+ # Running the command using Subprocess and capturing the output
150
+ completed_process = subprocess.run(command, text=True, stdout=subprocess.PIPE)
151
+
152
+ if completed_process.returncode != 0:
153
+ print(f"yt-dlp error in _get_supported_media_formats:")
154
+ print(completed_process.stderr)
155
+ else:
156
+ output_lines = completed_process.stdout.split('\n')
157
+ output_lines = [line for line in output_lines if line.strip()]
158
+
159
+ # Create a list of dictionaries for each format entry
160
+ streams_details = []
161
+ for line in output_lines[2:]: # Skip the header lines
162
+ fields = line.split()
163
+ media_format = fields[1]
164
+ media_quality = fields[-2]
165
+ if media_format in ['mp4', 'webm']:
166
+ if 'p,' in media_quality:
167
+ media_type = 'video'
168
+ media_quality = media_quality[:-1]
169
+ progressive = False
170
+ stream_details = [media_type, media_format, media_quality, progressive]
171
+ streams_details.append(stream_details)
172
+
173
+ # Create a pandas DataFrame from the list of dictionaries
174
+ cols = ['media_type', 'media_format', 'media_quality', 'progressive']
175
+ streams_df = pd.DataFrame(streams_details, columns=cols)
176
+ streams_df = streams_df.drop_duplicates().reset_index(drop=True)
177
+
178
+ # Adding Custom Audio Streams
179
+ streams_df.loc[len(streams_df)] = ['audio', 'mp3', '128kbps', False]
180
+ streams_df.loc[len(streams_df)] = ['audio', 'mp3', '256kbps', False]
181
+ streams_df.loc[len(streams_df)] = ['audio', 'wav', '1411kbps', False]
182
+
183
+ # Converting to Dictionary for Unique User Options
184
+ media_formats_dict = dict()
185
+ for media_type in sorted(streams_df['media_type'].unique()):
186
+ media_formats_dict[media_type] = dict()
187
+ media_type_df = streams_df[streams_df['media_type'] == media_type]
188
+ for media_format in sorted(media_type_df['media_format'].unique()):
189
+ media_format_df = media_type_df[media_type_df['media_format'] == media_format]
190
+ media_qualities = sorted(media_format_df['media_quality'].unique(), key=self.__get_quality_int)
191
+ media_formats_dict[media_type][media_format] = media_qualities
192
+
193
+ return streams_df, media_formats_dict
194
+
195
+ except Exception as yt_dlp_error:
196
+ print(f"yt-dlp error in _get_supported_media_formats: \n{yt_dlp_error}\n")
197
 
198
+ def select_media_format(self):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  '''
200
  For selecting media format to download
201
  '''
 
258
 
259
  return output_path
260
 
 
261
  def _download_audio(self, audio_format, audio_quality):
262
  '''
263
  Filters the required audio stream & downloads it
264
  '''
265
+
266
+ try:
267
+ # Getting Quality Command String
268
+ quality = str(self.__get_quality_int(audio_quality)) + 'K'
269
 
270
+ # Getting Output Path
271
+ output_path = os.path.join(self.output_path, f"{self.title}.{audio_format}")
 
 
 
272
 
273
+ # Download Command
274
+ command = [
275
+ "yt-dlp",
276
+ "-x", "--audio-format", audio_format,
277
+ "--audio-quality", quality,
278
+ "-o", output_path,
279
+ self.url, "-q"
280
+ ]
281
 
282
+ # Running the command using Subprocess
283
+ subprocess.run(command)
284
 
285
+ return output_path
286
+
287
+ except Exception as yt_dlp_error:
288
+ print(f"Error in _download_audio: \n{yt_dlp_error}\n")
289
 
290
  def _download_video(self, video_format, video_quality):
291
  '''
292
  Filters the required video stream & downloads it
293
  Only for Progressive media i.e containing both audio & video streams
294
  '''
 
 
 
 
295
 
296
+ try:
297
+ stream = self.streams.filter(progressive=True, file_extension=video_format, resolution=video_quality).first()
298
+ print(stream)
299
+ video_path = stream.download(output_path=self.output_path, filename=f"{self.title}.{video_format}")
300
+ return video_path
301
+
302
+ except Exception as pytube_error:
303
+ print(f"PyTube error in _download_video: \n{pytube_error}\n")
304
+ print('Trying with yt-dlp...')
305
+
306
+ try:
307
+ # Getting Output Path
308
+ output_path = os.path.join(self.output_path, f"{self.title}.{video_format}")
309
 
310
+ # Getting Video Quality Integer
311
+ video_quality = self.__get_quality_int(video_quality)
 
 
 
312
 
313
+ # Setting Formats
314
+ if video_format == 'mp4':
315
+ video_codec = "h264"
316
+ audio_codec = "m4a"
 
317
 
318
+ elif video_format == 'webm':
319
+ video_codec = "vp9"
320
+ audio_codec = "opus"
 
 
 
321
 
322
+ else:
323
+ print('Unexpected Video Format Encountered:', video_format)
324
+ os.exit(0)
325
 
326
+ # Download Command
327
+ command = [
328
+ "yt-dlp",
329
+ url,
330
+ "-S", f"res:{video_quality},vcodec:{video_codec},acodec:{audio_codec}",
331
+ "--merge-output-format", video_format,
332
+ "-o", f"{output_path}",
333
+ "-q"
334
+ ]
335
+ print(' '.join(command))
336
+
337
+ # Running the command using Subprocess
338
+ subprocess.run(command, check=True)
339
+
340
+ return output_path
341
+
342
+ except Exception as yt_dlp_error:
343
+ print(f"yt-dlp error in _download_video: \n{yt_dlp_error}\n")
344
+
345
+ def _download_audio_and_video(self, media_format, media_quality):
346
+ '''
347
+ Filters the required video stream & downloads it
348
+ Filters the best quality audio stream of the same format & downloads it
349
+ '''
350
+
351
+ try:
352
+ # Downloading Audio
353
+ stream = self.streams.filter(file_extension=media_format, only_audio=True).order_by('abr').desc().first()
354
+ print(stream)
355
+ audio_filename = f"{self.title} - Audio.{media_format}"
356
+ audio_path = stream.download(output_path=self.output_path, filename=audio_filename)
357
+
358
+ # Downloading Video
359
+ stream = self.streams.filter(file_extension=media_format, resolution=media_quality).first()
360
+ print(stream)
361
+ video_filename = f"{self.title} - Video.{media_format}"
362
+ video_path = stream.download(output_path=self.output_path, filename=video_filename)
363
+
364
+ # Combining the Audio & Video Files using FFMPEG Command
365
+ output_path = os.path.join(self.output_path, f"{self.title}.{media_format}")
366
+ command = ['ffmpeg', '-i', video_path, '-i', audio_path,
367
+ '-c:v', 'copy', '-c:a', 'copy', output_path,
368
+ '-loglevel', 'quiet']
369
+ subprocess.run(command)
370
+
371
+ os.remove(audio_path)
372
+ os.remove(video_path)
373
+
374
+ return output_path
375
+
376
+ except Exception as pytube_error:
377
+ print(f"PyTube error in _download_audio_and_video: \n{pytube_error}\n")
378
+ print('Trying with yt-dlp...')
379
+
380
+ try:
381
+
382
+ # Getting Output Path
383
+ output_path = os.path.join(self.output_path, f"{self.title}.{media_format}")
384
+
385
+ # Getting Video Quality Integer
386
+ media_quality = self.__get_quality_int(media_quality)
387
+
388
+ # Setting Formats
389
+ if media_format == 'mp4':
390
+ video_codec = "h264"
391
+ audio_codec = "m4a"
392
+
393
+ elif media_format == 'webm':
394
+ video_codec = "vp9"
395
+ audio_codec = "opus"
396
+
397
+ else:
398
+ print('Unexpected Video Format Encountered:', media_format)
399
+ os.exit(0)
400
+
401
+ # Download Command
402
+ command = [
403
+ "yt-dlp",
404
+ url,
405
+ "-S", f"res:{media_quality},vcodec:{video_codec},acodec:{audio_codec}",
406
+ "--merge-output-format", media_format,
407
+ "-o", f"{output_path}",
408
+ "-q"
409
+ ]
410
+ print(' '.join(command))
411
+
412
+ # Running the command using Subprocess
413
+ subprocess.run(command)
414
+
415
+ return output_path
416
+
417
+ except Exception as yt_dlp_error:
418
+ print(f"yt-dlp error in _download_audio_and_video: \n{yt_dlp_error}\n")
419
 
420
  def _download_media_chunk(self, media_type, media_format, media_quality):
421
  '''
 
435
  '''
436
  Filters the required audio stream & downloads it for particular chunk
437
  '''
438
+
439
+ try:
440
+ # Getting Chunk Command String
441
+ if (self.start_time) and (self.end_time):
442
+ chunk_string = f"-ss {self.start_time} -to {self.end_time}"
443
 
444
+ elif (self.start_time) and (not self.end_time):
445
+ chunk_string = f"-ss {self.start_time}"
 
 
 
 
446
 
447
+ elif (not self.start_time) and (self.end_time):
448
+ chunk_string = f"-to {self.end_time}"
449
 
450
+ # Getting Quality Command String
451
+ quality = str(self.__get_quality_int(audio_quality)) + 'K'
452
 
453
+ # Getting Output Path
454
+ output_path = os.path.join(self.output_path, f"{self.title}.{audio_format}")
455
 
456
+ # Download Command
457
+ command = [
458
+ "yt-dlp",
459
+ "-x", "--audio-format", audio_format,
460
+ "--audio-quality", quality,
461
+ "--external-downloader", "ffmpeg",
462
+ "--external-downloader-args", chunk_string,
463
+ "-o", output_path,
464
+ url, "-q"
465
+ ]
466
 
467
+ # Running the command using Subprocess
468
+ subprocess.run(command)
469
 
470
+ return output_path
471
+
472
+ except Exception as e:
473
+ print(f"Error in _download_audio_chunk: {e}")
474
 
475
  def _download_video_chunk(self, video_format, video_quality):
476
  '''
477
  Filters the required video stream & downloads it for particular chunk
478
  '''
479
 
480
+ try:
481
+ # Getting Chunk Command String
482
+ if (self.start_time) and (self.end_time):
483
+ chunk_string = f"-ss {self.start_time} -to {self.end_time}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
 
485
+ elif (self.start_time) and (not self.end_time):
486
+ chunk_string = f"-ss {self.start_time}"
487
 
488
+ elif (not self.start_time) and (self.end_time):
489
+ chunk_string = f"-to {self.end_time}"
490
 
491
+ # Getting Output Path
492
+ output_path = os.path.join(self.output_path, f"{self.title}.{video_format}")
 
 
 
 
 
 
 
 
 
 
 
493
 
494
+ # Getting Video Quality Integer
495
+ video_quality = self.__get_quality_int(video_quality)
496
 
497
+ # Setting Formats
498
+ if video_format == 'mp4':
499
+ video_codec = "h264"
500
+ audio_codec = "m4a"
 
 
 
501
 
502
+ elif video_format == 'webm':
503
+ video_codec = "vp9"
504
+ audio_codec = "opus"
505
 
506
+ else:
507
+ print('Unexpected Video Format Encountered:', video_format)
508
+ os.exit(0)
509
+
510
+ # Download Command
511
+ command = [
512
+ "yt-dlp",
513
+ url,
514
+ "-S", f"res:{video_quality},vcodec:{video_codec},acodec:{audio_codec}",
515
+ "--merge-output-format", video_format,
516
+ "--download-sections", f"*{self.start_time}-{self.end_time}",
517
+ "-o", f"{output_path}",
518
+ "-q"
519
+ ]
520
+
521
+ print(' '.join(command))
522
+
523
+ # Running the command using Subprocess
524
+ subprocess.run(command)
525
+
526
+ return output_path
527
 
528
+ except Exception as e:
529
+ print(f"Error in _download_video_chunk: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
summarizer.py CHANGED
@@ -415,13 +415,13 @@ class AudioBookNarration:
415
  def get_stuff_prompt(self):
416
 
417
  prompt_template = """
418
- Create a {Narration_style} narration for this below text. This narration will be used for audiobook generation.
419
  So provide the output that is verbose, easier to understand and full of expressions.
420
  {text}
421
 
422
  """
423
  prompt = PromptTemplate(
424
- template=prompt_template, input_variables=['Narration_style','text'])
425
 
426
 
427
  return prompt
@@ -429,29 +429,29 @@ class AudioBookNarration:
429
  def define_prompts(self):
430
 
431
  map_prompts = """
432
- Create a {Narration_style} narration for this below text. This narration will be used for audiobook generation.
433
  So provide the output that is verbose, easier to understand and full of expressions.
434
  {text}
435
  """
436
 
437
  combine_prompt = """
438
  Below are the list of text that represent narration from the text.
439
- Your job is to combine these narrations and craete one verbose,easier to understand and full of experssions {Narration_style} narration.
440
  {text}
441
 
442
  """
443
 
444
 
445
 
446
- map_template = PromptTemplate(template=map_prompts, input_variables=['Narration_style','text']
447
  )
448
  combine_template = PromptTemplate(
449
- template=combine_prompt, input_variables=['Narration_style','text'])
450
 
451
  return map_template, combine_template
452
  # pass
453
 
454
- def define_chain(self,Narration_style=None,chain_type=None):
455
 
456
 
457
  docs, chain_type = self.load_docs()
@@ -470,7 +470,7 @@ class AudioBookNarration:
470
  llm=llm, map_prompt=map_prompts, combine_prompt=combine_prompt, chain_type='map_reduce', verbose=False)
471
 
472
 
473
- output = chain.run(Narration_style = Narration_style,input_documents = docs)
474
 
475
  # self.create_wordcloud(output=output)
476
  # display(Markdown(f"Text: {docs}"))
 
415
  def get_stuff_prompt(self):
416
 
417
  prompt_template = """
418
+ Create a {narration_style} narration for this below text. This narration will be used for audiobook generation.
419
  So provide the output that is verbose, easier to understand and full of expressions.
420
  {text}
421
 
422
  """
423
  prompt = PromptTemplate(
424
+ template=prompt_template, input_variables=['narration_style','text'])
425
 
426
 
427
  return prompt
 
429
  def define_prompts(self):
430
 
431
  map_prompts = """
432
+ Create a {narration_style} narration for this below text. This narration will be used for audiobook generation.
433
  So provide the output that is verbose, easier to understand and full of expressions.
434
  {text}
435
  """
436
 
437
  combine_prompt = """
438
  Below are the list of text that represent narration from the text.
439
+ Your job is to combine these narrations and craete one verbose,easier to understand and full of experssions {narration_style} narration.
440
  {text}
441
 
442
  """
443
 
444
 
445
 
446
+ map_template = PromptTemplate(template=map_prompts, input_variables=['narration_style','text']
447
  )
448
  combine_template = PromptTemplate(
449
+ template=combine_prompt, input_variables=['narration_style','text'])
450
 
451
  return map_template, combine_template
452
  # pass
453
 
454
+ def define_chain(self,narration_style=None,chain_type=None):
455
 
456
 
457
  docs, chain_type = self.load_docs()
 
470
  llm=llm, map_prompt=map_prompts, combine_prompt=combine_prompt, chain_type='map_reduce', verbose=False)
471
 
472
 
473
+ output = chain.run(narration_style = narration_style,input_documents = docs)
474
 
475
  # self.create_wordcloud(output=output)
476
  # display(Markdown(f"Text: {docs}"))
temp/translated_subtitles.json ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "start":0.0,
4
+ "end":6.0,
5
+ "text":"دوسرا پہلو ٹیلی ویژن اور فلمیں اور موسیقی ہے۔"
6
+ },
7
+ {
8
+ "start":6.0,
9
+ "end":12.0,
10
+ "text":"اسلام کے بارے میں دلچسپ باتوں میں سے ایک یہ ہے کہ علمائے کرام کا موسیقی کے ساتھ تناؤ تھا۔"
11
+ },
12
+ {
13
+ "start":12.0,
14
+ "end":17.0,
15
+ "text":"کوئی بھی یہ واضح بیان نہیں دے سکتا کہ یہ مجمل ہے۔"
16
+ },
17
+ {
18
+ "start":17.0,
19
+ "end":26.0,
20
+ "text":"اگر آپ شوکانی اور نیل الاوطار پڑھیں تو اس کے پاس اس پر ایک سیکشن ہے اور اس میں موسیقی کے بارے میں موجود خلافت کے بارے میں بات کرتا ہے۔"
21
+ },
22
+ {
23
+ "start":30.0,
24
+ "end":38.18,
25
+ "text":"سماع کے بارے میں علماء کے حصے ہیں جو کہ موسیقی کی ایک مقدس قسم ہے جسے وہ اچھی چیز اور جائز سمجھتے تھے۔"
26
+ },
27
+ {
28
+ "start":39.0,
29
+ "end":46.0,
30
+ "text":"لیکن علمائے کرام موسیقی سے بہت محتاط تھے کیونکہ وہ سمجھتے تھے کہ موسیقی کتنی طاقتور ہے،"
31
+ },
32
+ {
33
+ "start":46.0,
34
+ "end":50.0,
35
+ "text":"اور یہ کتنا پرکشش ہے، اور اس کے روح پر کیا اثرات مرتب ہوتے ہیں۔"
36
+ },
37
+ {
38
+ "start":50.0,
39
+ "end":53.0,
40
+ "text":"یہ اصل میں قدیم یونانیوں کو واپس جاتا ہے."
41
+ },
42
+ {
43
+ "start":53.0,
44
+ "end":58.0,
45
+ "text":"جمہوریہ میں افلاطون، سقراط وہ آواز ہے جسے وہ استعمال کرتا ہے۔"
46
+ },
47
+ {
48
+ "start":60.0,
49
+ "end":67.0,
50
+ "text":"وہ دراصل جمہوریہ میں موسیقی کی کچھ اقسام کو غیر قانونی قرار دیتا ہے کیونکہ وہ روح کے لیے بہت نقصان دہ تھے۔"
51
+ },
52
+ {
53
+ "start":67.0,
54
+ "end":71.0,
55
+ "text":"ایتھوس تھیوری موسیقی کے اثر کا نظریہ ہے۔"
56
+ },
57
+ {
58
+ "start":71.0,
59
+ "end":79.0,
60
+ "text":"درحقیقت الفارابی جس نے موسیقی کی سب سے بڑی کتاب کتاب الموسیق الکبیر لکھی۔"
61
+ },
62
+ {
63
+ "start":79.0,
64
+ "end":83.0,
65
+ "text":"جو میری لائبریری میں ہے، یہ ایک بہت بڑی کتاب ہے، بہت بھاری۔"
66
+ },
67
+ {
68
+ "start":83.0,
69
+ "end":89.0,
70
+ "text":"یہ موسیقی کی سائنس پر ابتدائی سنجیدہ کاموں میں سے ایک ہے۔"
71
+ },
72
+ {
73
+ "start":90.0,
74
+ "end":103.0,
75
+ "text":"وہ لوگوں کو ہنسانے، رونے، نیند آنے، یا مقام کی بنیاد پر پرجوش ہونے کے قابل ہونے کے لیے جانا جاتا تھا جو وہ عود پر بجاتا تھا۔"
76
+ },
77
+ {
78
+ "start":104.04,
79
+ "end":106.0,
80
+ "text":"وہ لفظی طور پر لوگوں کو رلا سکتا تھا۔"
81
+ },
82
+ {
83
+ "start":106.0,
84
+ "end":107.36,
85
+ "text":"اور یہ اچھی طرح سے درج ہے۔"
86
+ },
87
+ {
88
+ "start":108.66,
89
+ "end":112.0,
90
+ "text":"اور جب لوگ کنسرٹس میں جاتے ہیں تو آپ کو یہی ملتا ہے۔"
91
+ },
92
+ {
93
+ "start":112.0,
94
+ "end":115.0,
95
+ "text":"وہ بہت مشتعل ہو جاتے ہیں، انہیں حرکت کرنا پڑتی ہے۔"
96
+ },
97
+ {
98
+ "start":115.0,
99
+ "end":117.0,
100
+ "text":"وہ نہیں جانتے کیوں، لیکن انہیں منتقل ہونا پڑے گا."
101
+ },
102
+ {
103
+ "start":120.0,
104
+ "end":127.0,
105
+ "text":"آوازوں کے شیطانی اثرات ہوتے ہیں، اور پھر فرشتے کے اثرات ہوتے ہیں جو آوازوں کے ہوتے ہیں۔"
106
+ },
107
+ {
108
+ "start":127.0,
109
+ "end":133.0,
110
+ "text":"اور یوں علمائے کرام آواز کے شیطانی اثرات کے بارے میں بہت فکر مند تھے۔"
111
+ },
112
+ {
113
+ "start":134.08,
114
+ "end":141.0,
115
+ "text":"اور وہ سمجھ گئے کہ جن چیزوں کو شیاطین ہمیشہ استعمال کرتے رہے ہیں وہ موسیقی ہے لوگوں کو اپنی طرف راغب کرنے کے لیے۔"
116
+ },
117
+ {
118
+ "start":141.0,
119
+ "end":146.34,
120
+ "text":"درحقیقت داؤد علیہ السلام کے بارے میں حدیث میں ہے کہ جنہوں نے زبور گایا،"
121
+ },
122
+ {
123
+ "start":150.0,
124
+ "end":153.0,
125
+ "text":"یہ روحانی نہیں تھا، لیکن یہ فرشتہ تھا۔"
126
+ },
127
+ {
128
+ "start":153.46,
129
+ "end":158.0,
130
+ "text":"شیطان نے ایک چھوٹا سا بینڈ اکٹھا کیا، اور اس نے اسے سڑک کے کنارے رکھ دیا،"
131
+ },
132
+ {
133
+ "start":158.0,
134
+ "end":162.78,
135
+ "text":"اور لوگ داؤد کو سننے کے لیے جاتے تھے اور شیطان کے ٹولے کو سنتے تھے۔"
136
+ },
137
+ {
138
+ "start":163.0,
139
+ "end":166.0,
140
+ "text":"اور وہ داؤد کو بھول جائیں گے۔"
141
+ },
142
+ {
143
+ "start":166.0,
144
+ "end":170.0,
145
+ "text":"اور یوں یہ وہ تناؤ تھا جو علمائے کرام کو تھا، اور یہ بہت ضروری ہے کہ یہ تناؤ موجود رہے،"
146
+ },
147
+ {
148
+ "start":170.08,
149
+ "end":175.0,
150
+ "text":"کیونکہ کوئی بھی یہ بیان نہیں کر سکتا کہ موسیقی مکمل طور پر حرام ہے،"
151
+ },
152
+ {
153
+ "start":175.0,
154
+ "end":178.0,
155
+ "text":"اور کوئی بھی یہ نہیں کہہ سکتا کہ یہ حلال ہے۔"
156
+ },
157
+ {
158
+ "start":180.0,
159
+ "end":185.0,
160
+ "text":"اور مسلمان اس چیز میں کبھی زیادہ دور نہیں جاتے، کیونکہ اب آپ مغرب میں دیکھتے ہیں،"
161
+ },
162
+ {
163
+ "start":185.46,
164
+ "end":189.0,
165
+ "text":"لوگ ہر وقت موسیقی سنتے ہیں، ان کے پاس نہیں ہے، وہ ہمیشہ پلگ ان ہوتے ہیں۔"
166
+ },
167
+ {
168
+ "start":189.0,
169
+ "end":190.84,
170
+ "text":"وہ اپنی گاڑی میں بیٹھتے ہیں، وہ میوزک آن کرتے ہیں۔"
171
+ },
172
+ {
173
+ "start":191.0,
174
+ "end":195.0,
175
+ "text":"وہ چلتے ہیں، وہ اپنے ائرفون لگاتے ہیں، اور وہ اپنی موسیقی سنتے ہیں،"
176
+ },
177
+ {
178
+ "start":195.0,
179
+ "end":199.0,
180
+ "text":"اور لوگوں کے پاس لمبی پلے لسٹ ہوتی ہے، وہ ان چیزوں پر بہت پیسہ خرچ کرتے ہیں،"
181
+ },
182
+ {
183
+ "start":199.0,
184
+ "end":204.0,
185
+ "text":"اور اس طرح وہ کھو گئے ہیں، ان کے پاس مزید سوچنے کا وقت نہیں ہے،"
186
+ },
187
+ {
188
+ "start":204.0,
189
+ "end":206.0,
190
+ "text":"کیونکہ ان کی زندگی آوازوں سے بھری ہوئی ہے۔"
191
+ },
192
+ {
193
+ "start":210.0,
194
+ "end":215.0,
195
+ "text":"جو ان کے پاس پہلے کبھی نہیں تھا، اور وہ انہیں بہت مؤثر طریقے سے استعمال کر رہے ہیں۔"
196
+ },
197
+ {
198
+ "start":215.3,
199
+ "end":221.0,
200
+ "text":"اور بدقسمتی سے ہم حق کے لوگ ان کا مؤثر استعمال نہیں کر رہے ہیں۔"
201
+ },
202
+ {
203
+ "start":221.0,
204
+ "end":222.0,
205
+ "text":"اور اللہ فرماتا ہے"
206
+ },
207
+ {
208
+ "start":226.0,
209
+ "end":229.0,
210
+ "text":"ان اوزاروں سے لڑو جن سے آپ لڑ رہے ہیں۔"
211
+ },
212
+ {
213
+ "start":229.0,
214
+ "end":234.0,
215
+ "text":"اس دور کا جہاد کانوں کے درمیان ہے۔"
216
+ },
217
+ {
218
+ "start":234.0,
219
+ "end":238.0,
220
+ "text":"اس دور کا جہاد کانوں کے درمیان ہے۔"
221
+ },
222
+ {
223
+ "start":240.0,
224
+ "end":245.0,
225
+ "text":"میدان جنگ انسانوں کا دماغ ہے اور وسعت کے لحاظ سے دل۔"
226
+ }
227
+ ]
temp/translated_transcript.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ دوسرا پہلو ٹیلی ویژن، فلمیں اور موسیقی ہے. اسلام کے بارے میں ایک دلچسپ بات یہ ہے کہ علماء کی موسیقی کے ساتھ کشیدگی تھی. کوئی بھی یہ بات واضح نہیں کر سکتا کہ یہ مجمل علی ہے. اگر آپ شوکانی اور نائل الاوطار پڑھتے ہیں تو اس کے پاس اس پر ایک سیکشن ہے اور وہ موسیقی کے بارے میں موجود خلافت کے بارے میں بات کرتا ہے. علماء کے پاس سما کے بارے میں سیکشن ہیں، جو ایک مقدس قسم کی موسیقی ہے جو ان کے خیال میں ایک اچھی چیز اور جائز ہے. لیکن علماء موسیقی سے بہت محتاط تھے کیونکہ وہ سمجھتے تھے کہ موسیقی کتنی طاقتور ہے اور کتنی دلکش ہے، اور روح پر اس کے اثرات. یہ اصل میں قدیم یونانیوں سے واپس جاتا ہے. جمہوریہ میں افلاطون، سقراط وہ آواز ہے جو وہ استعمال کرتا ہے. وہ اصل میں جمہوریہ میں موسیقی کی کچھ اقسام کو غیر قانونی قرار دیتا ہے کیونکہ وہ روح کے لئے بہت نقصان دہ تھے. ایتوس تھیوری اس اثر کا نظریہ ہے کہ موسیقی. دراصل، الفارابی، جس نے کتب الموسيق الكبير لکھی، موسیقی کی بڑی کتاب، جو میرے پاس اپنی لائبریری میں ہے، یہ ایک بہت بڑی کتاب ہے، بہت بھاری. یہ موسیقی کے علم پر سب سے پہلے سنجیدہ کام میں سے ایک ہے. وہ لوگوں کو ہنسنے ، رونے ، نیند آنے یا شوق سے کھیلنے کے قابل ہونے کے لئے جانا جاتا تھا. وہ لفظی طور پر لوگوں کو روانا کر سکتا تھا. اور یہ اچھی طرح ریکارڈ کیا گیا ہے. اور یہ آپ کو ملتا ہے جب لوگ کنسرٹ پر جاتے ہیں. وہ بہت پریشان ہو جاتے ہیں، انہیں منتقل کرنا پڑتا ہے. وہ نہیں جانتے کیوں، لیکن وہ منتقل کرنا ہے. آوازوں کے شیطانی اثرات ہوتے ہیں، اور پھر فرشتے بھی ہوتے ہیں جن کے اثرات ہوتے ہیں. اور اس لئے علماء کو آواز کے شیطانی اثرات سے بہت فکر مند تھے. اور وہ سمجھ گئے کہ جنات نے ہمیشہ لوگوں کو دور کرنے کے لئے موسیقی کا استعمال کیا ہے. دراصل، داؤد، سلام ہو اس پر، جو زبور گاتا تھا کے بارے میں حدیث میں، یہ روحانی نہیں تھا، لیکن یہ فرشتہ تھا. شیطان نے ایک چھوٹا سا بینڈ اکٹھا کیا اور اس نے اسے سڑک کے کنارے رکھا اور لوگ جو داؤد کو سننے کے لئے جا رہے تھے وہ رک کر شیطان کے بینڈ کو سنتے تھے اور وہ داؤد کو بھول جاتے تھے. اور تو یہ کشیدگی تھی جو علماء نے کی تھی، اور یہ بہت اہم ہے کہ کشیدگی موجود ہے کیونکہ کوئی بھی ایک جامع بیان نہیں دے سکتا کہ موسیقی مکمل طور پر حرام ہے، اور کوئی بھی ایک جامع بیان نہیں دے سکتا کہ یہ حلال ہے. اور مسلمانوں کو کبھی بھی اس چیز میں بہت زیادہ نہیں جانا کیونکہ اب آپ دیکھ سکتے ہیں کہ مغرب میں لوگ ہر وقت موسیقی سنتے ہیں، ان کے پاس نہیں ہے، وہ ہمیشہ پلگ ان ہیں. وہ اپنی گاڑیوں میں جاتے ہیں، وہ موسیقی کو چالو کرتے ہیں. وہ چلتے ہیں، وہ اپنے کانوں میں رکھتے ہیں، اور وہ اپنی موسیقی سنتے ہیں، اور لوگوں کے پاس لمبی پلے لسٹس ہیں، وہ ان چیزوں پر بہت پیسہ خرچ کرتے ہیں، اور اس طرح وہ کھو گئے ہیں، ان کے پاس سوچنے کے لئے زیادہ مفت وقت نہیں ہے کیونکہ ان کی زندگی ایسی آواز سے بھری ہوئی ہے جو ان کے پاس پہلے کبھی نہیں تھی، اور وہ ان کا استعمال بہت مؤثر طریقے سے کر رہے ہیں. اور ہم، بدقسمتی سے، حق کے لوگ، ان کا مؤثر طریقے سے استعمال نہیں کر رہے ہیں بالکل. اور اللہ تعالیٰ فرماتا ہے، "جو اوزار سے تم لڑ رہے ہو ان سے لڑو. اس زمانے کا جہاد کانوں کے درمیان ہے. اس زمانے کا جہاد کانوں کے درمیان ہے. میدانِ جنگ انسانوں کا ذہن ہے اور اس کے علاوہ دل بھی. ".
translation.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import openai
3
+
4
+ import locale
5
+ locale.getpreferredencoding = lambda: "UTF-8"
6
+
7
+ import dl_translate as dlt
8
+ from deep_translator import GoogleTranslator
9
+
10
+ from languages import LANGUAGES
11
+
12
+
13
+ OPENAI_API_KEY = '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'
14
+ OPENAI_API_URL = 'https://api.openai.com/v1/chat/completions'
15
+ openai.api_key = OPENAI_API_KEY
16
+
17
+ class Translation:
18
+
19
+ def __init__(self, transcript_dict, source_lang, target_lang, output_path):
20
+ self.transcript_dict = transcript_dict
21
+ self.output_path = os.path.join(os.getcwd(), output_path)
22
+
23
+ # Languages
24
+ self.source_lang = source_lang # Whisper Detected Language
25
+ self.target_lang = target_lang
26
+
27
+ # Transcript
28
+ self.transcript = transcript_dict['text'].strip()
29
+ self.subtitles = self.__get_subtitles()
30
+
31
+ # Translation Model
32
+ nllb_model = 'facebook/nllb-200-distilled-600M'
33
+ # nllb_model = 'facebook/nllb-200-1.3B'
34
+ # nllb_model = 'facebook/nllb-200-3.3B'
35
+ # nllb_model = 'facebook/nllb-moe-54b'
36
+ self.nllb = dlt.TranslationModel(nllb_model)
37
+
38
+ def __get_subtitles(self):
39
+ '''
40
+ Returns the subtitles from transcript dictionary
41
+ '''
42
+
43
+ subtitles = []
44
+ for s in self.transcript_dict['segments']:
45
+ segment = {
46
+ 'start': s['start'],
47
+ 'end': s['end'],
48
+ 'text': s['text'].strip()
49
+ }
50
+ subtitles.append(segment)
51
+ return subtitles
52
+
53
+ def __correct_punctuation_gpt(self):
54
+ '''
55
+ Corrects the Punctuation from GPT
56
+ '''
57
+
58
+ system_prompt = """
59
+ You are a helpful NLP assistant.
60
+ Your task is to identify language of the provided text,
61
+ correct any spelling discrepancies in the transcribed text
62
+ as well as add punctuation in the multilingual text if they are missing.
63
+ Only add necessary punctuation such as periods, commas, and capitalization,
64
+ and use only the context provided.
65
+
66
+ You response should be as follows:
67
+ Corrected Text:
68
+ Here goes the corrected text with punctuation.
69
+ """
70
+
71
+ user_prompt = f"""
72
+ Here is the text:
73
+ {self.transcript}
74
+ """
75
+
76
+ response = openai.ChatCompletion.create(
77
+ model="gpt-3.5-turbo",
78
+ messages=[
79
+ {"role": "system", "content": system_prompt},
80
+ {"role": "user", "content": user_prompt},
81
+ ]
82
+ )
83
+
84
+ text = response.choices[0].message.content.replace('Corrected Text:\n', '')
85
+ return text
86
+
87
+ def get_translated_transcript(self):
88
+ '''
89
+ Translates the transcript into required language
90
+ '''
91
+
92
+ # Correcting Punctuation using GPT
93
+ transcript = self.__correct_punctuation_gpt()
94
+
95
+ # Splitting Text into Sentences
96
+ if self.source_lang in ['ar', 'ur']:
97
+ splitter = '۔'
98
+ else:
99
+ splitter = '.'
100
+ sentences = transcript.split(splitter)
101
+
102
+ # Getting Translation using NLLB
103
+ translated_transcript = ''
104
+ for sentence in sentences:
105
+ translated_sentence = self.nllb.translate(sentence, source=LANGUAGES[self.source_lang], target=LANGUAGES[self.target_lang])
106
+ translated_transcript += translated_sentence + splitter + ' '
107
+ # print('Text:', sentence)
108
+ # print('Text:', translated_sentence)
109
+ # print()
110
+ translated_transcript = translated_transcript.strip()
111
+
112
+ return translated_transcript
113
+
114
+ def get_translated_subtitles(self):
115
+ '''
116
+ Translates the subtitles into required language
117
+ '''
118
+
119
+ # Creating copy of Transcript Dictionary
120
+ subtitles = self.subtitles.copy()
121
+
122
+ # Creating Instance for Google Translator
123
+ gt = GoogleTranslator(source='auto', target=self.target_lang)
124
+ for i, s in enumerate(subtitles):
125
+ subtitles[i]['text'] = gt.translate(text=s['text'])
126
+
127
+ return subtitles