DARKWICK commited on
Commit
29378ed
·
verified ·
1 Parent(s): d07a60d

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +31 -7
  2. app.py +415 -0
  3. gitattributes +35 -0
  4. requirements.txt +9 -0
README.md CHANGED
@@ -1,12 +1,36 @@
1
  ---
2
- title: Dollu Baba
3
- emoji: 🔥
4
- colorFrom: blue
5
  colorTo: blue
6
- sdk: docker
 
 
7
  pinned: false
8
- license: mit
9
- short_description: Elvtr
10
  ---
 
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: YouTube Translator and Speaker
3
+ emoji: 🌍
4
+ colorFrom: yellow
5
  colorTo: blue
6
+ sdk: gradio
7
+ sdk_version: 5.28.0
8
+ app_file: app.py
9
  pinned: false
 
 
10
  ---
11
+ # YouTube Translator and Speaker
12
 
13
+ This HuggingFace Space application allows you to get the translated transcript and speech for a given YouTube video.
14
+
15
+ ## guide
16
+
17
+ 1. Enter the YouTube Video ID in the provided text box.
18
+ (The video ID is the unique string of characters in the YouTube video URL after `v=`, e.g., `dQw4w9WgXcQ`)
19
+ 2. Select the target language from the dropdown menu.
20
+ 3. The translated text will appear in the 'Translated Text' box, and the translated speech will play automatically.
21
+
22
+ ## SupporteWorking Languages
23
+
24
+ - Arabic (ar)
25
+ - French (fr)
26
+ - Hausa (ha)
27
+ - Afghan Persian / Dari (fa)
28
+ - Pashto (ps)
29
+
30
+ ## Key Notes
31
+
32
+ - Translation for Arabic and French uses Helsinki-NLP models.
33
+ - Translation for Hausa, Afghan Persian, and Pashto uses the Facebook NLLB-200 model.
34
+ - Speech generation for Arabic and French uses gTTS.
35
+ - Speech generation for Hausa, Afghan Persian, and Pashto uses the ElevenLabs API. An ElevenLabs API key is required as a Space secret named `ELEVENLABS_API_KEY` for speech to work in these languages.
36
+ - Proxy settings for YouTube transcript retrieval can be configured using Space secrets named `WEBSHARE_PROXY_UN` and `WEBSHARE_PROXY_PW`.
app.py ADDED
@@ -0,0 +1,415 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import torch
4
+ import os
5
+ from transformers import MarianMTModel, MarianTokenizer, AutoTokenizer, AutoModelForSeq2SeqLM
6
+ from youtube_transcript_api import YouTubeTranscriptApi
7
+ from youtube_transcript_api.proxies import WebshareProxyConfig
8
+ from gtts import gTTS
9
+
10
+ # Initialize YouTubeTranscriptApi
11
+ proxy_username = os.environ.get('WEBSHARE_PROXY_UN')
12
+ proxy_password = os.environ.get('WEBSHARE_PROXY_PW')
13
+
14
+ ytt_api = None
15
+ try:
16
+ if proxy_username and proxy_password:
17
+ ytt_api = YouTubeTranscriptApi(
18
+ proxy_config=WebshareProxyConfig(
19
+ proxy_username=proxy_username,
20
+ proxy_password=proxy_password,
21
+ filter_ip_locations=["us"],
22
+ )
23
+ )
24
+ print(f"Successfully connected to the Youtube API with proxy.")
25
+ else:
26
+ ytt_api = YouTubeTranscriptApi()
27
+ print(f"Successfully connected to the Youtube API without proxy.")
28
+ except Exception as e:
29
+ print(f"A proxy error occurred in connecting to the Youtube API: {e}")
30
+ ytt_api = YouTubeTranscriptApi() # Fallback if proxy fails
31
+
32
+
33
+ def getEnglishTranscript(video_id):
34
+ """Retrieves the English transcript for a given YouTube video ID."""
35
+ if not ytt_api:
36
+ print("YouTubeTranscriptApi not initialized.")
37
+ return ""
38
+
39
+ try:
40
+ transcript_list = ytt_api.list(video_id)
41
+ english_original = None
42
+ for transcript in transcript_list:
43
+ if(transcript.language_code == 'en'):
44
+ english_original = transcript.fetch()
45
+ break
46
+ english_output = ""
47
+ if english_original:
48
+ for snippet in english_original:
49
+ english_output += snippet.text + " "
50
+ else:
51
+ print(f"No English transcript found for video ID: {video_id}")
52
+ return english_output.strip()
53
+ except Exception as e:
54
+ print(f"Error retrieving English transcript for video ID {video_id}: {e}")
55
+ return ""
56
+
57
+
58
+ def getArabicTranscript(video_id):
59
+ """Retrieves the Arabic transcript for a given YouTube video ID, translating if necessary."""
60
+ if not ytt_api:
61
+ print("YouTubeTranscriptApi not initialized.")
62
+ return ""
63
+
64
+ try:
65
+ transcript_list = ytt_api.list(video_id)
66
+ arabic_translation = None
67
+ for transcript in transcript_list:
68
+ if(transcript.is_translatable):
69
+ arabic_language_code = None
70
+ for lang in transcript.translation_languages:
71
+ if lang.language == 'Arabic':
72
+ arabic_language_code = lang.language_code
73
+ break
74
+ if arabic_language_code:
75
+ print(f"\nTranslating to Arabic ({arabic_language_code})...")
76
+ arabic_translation = transcript.translate(arabic_language_code).fetch()
77
+ print("Arabic Translation Found and Stored.")
78
+ break # Exit after finding the first Arabic translation
79
+ arabic_output = ""
80
+ if arabic_translation:
81
+ for snippet in arabic_translation:
82
+ arabic_output += snippet.text + " "
83
+ else:
84
+ print(f"No translatable transcript found for Arabic for video ID: {video_id}")
85
+ return arabic_output.strip()
86
+ except Exception as e:
87
+ print(f"Error retrieving or translating Arabic transcript for video ID {video_id}: {e}")
88
+ return ""
89
+
90
+
91
+ def getFrenchTranscript(video_id):
92
+ """Retrieves the French transcript for a given YouTube video ID, translating if necessary."""
93
+ if not ytt_api:
94
+ print("YouTubeTranscriptApi not initialized.")
95
+ return ""
96
+
97
+ try:
98
+ transcript_list = ytt_api.list(video_id)
99
+ french_translation = None
100
+ for transcript in transcript_list:
101
+ if(transcript.is_translatable):
102
+ french_language_code = None
103
+ for lang in transcript.translation_languages:
104
+ if lang.language == 'French':
105
+ french_language_code = lang.language_code
106
+ break
107
+ if french_language_code:
108
+ print(f"\nTranslating to French ({french_language_code})...")
109
+ french_translation = transcript.translate(french_language_code).fetch()
110
+ print("French Translation Found and Stored.")
111
+ break # Exit after finding the first French translation
112
+ french_output = ""
113
+ if french_translation:
114
+ for snippet in french_translation:
115
+ french_output += snippet.text + " "
116
+ else:
117
+ print(f"No translatable transcript found for French for video ID: {video_id}")
118
+ return french_output.strip()
119
+ except Exception as e:
120
+ print(f"Error retrieving or translating French transcript for video ID {video_id}: {e}")
121
+ return ""
122
+
123
+ model, tokenizer, device = None, None, None
124
+ formatted_language_code = ""
125
+
126
+ def setModelAndTokenizer(language_code):
127
+ """Sets the appropriate translation model and tokenizer based on the target language code."""
128
+ global model, tokenizer, device, formatted_language_code
129
+
130
+ _MODEL_NAME = None
131
+ _readable_name = None
132
+
133
+ if language_code == 'ar':
134
+ _MODEL_NAME = "Helsinki-NLP/opus-mt-tc-big-en-ar"
135
+ _readable_name = "English to Arabic"
136
+ elif language_code == 'fr':
137
+ _MODEL_NAME = "Helsinki-NLP/opus-mt-tc-big-en-fr"
138
+ _readable_name = "English to French"
139
+ elif language_code == 'ha':
140
+ _MODEL_NAME = "facebook/nllb-200-distilled-600M"
141
+ _readable_name = "English to Hausa"
142
+ formatted_language_code = "hau_Latn"
143
+ elif language_code == 'fa':
144
+ _MODEL_NAME = "facebook/nllb-200-distilled-600M"
145
+ _readable_name = "English to Dari/Afghan Persian"
146
+ formatted_language_code = "pes_Arab"
147
+ elif language_code == 'ps':
148
+ _MODEL_NAME = "facebook/nllb-200-distilled-600M"
149
+ _readable_name = "English to Pashto"
150
+ formatted_language_code = "pbt_Arab"
151
+ else:
152
+ return f"Language code '{language_code}' not supported for translation model."
153
+
154
+ if model is not None and tokenizer is not None and hasattr(tokenizer, 'name_or_path') and tokenizer.name_or_path == _MODEL_NAME:
155
+ print(f"Model and tokenizer for {_readable_name} already loaded.")
156
+ return f"Model and tokenizer for {_readable_name} already loaded."
157
+
158
+
159
+ print(f"Loading model and tokenizer for {_readable_name}...")
160
+ if "Helsinki-NLP" in _MODEL_NAME:
161
+ try:
162
+ tokenizer = MarianTokenizer.from_pretrained(_MODEL_NAME)
163
+ model = MarianMTModel.from_pretrained(_MODEL_NAME)
164
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
165
+ model.to(device)
166
+ print(f"Successfully loaded Helsinki-NLP model: {_MODEL_NAME}")
167
+ except Exception as e:
168
+ print(f"Error loading Helsinki-NLP model or tokenizer: {e}")
169
+ return "Error loading translation model."
170
+
171
+ elif "facebook" in _MODEL_NAME:
172
+ try:
173
+ tokenizer = AutoTokenizer.from_pretrained(_MODEL_NAME)
174
+ model = AutoModelForSeq2SeqLM.from_pretrained(_MODEL_NAME, device_map="auto")
175
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
176
+ model.to(device)
177
+ print(f"Successfully loaded Facebook NLLB model: {_MODEL_NAME}")
178
+ except Exception as e:
179
+ print(f"Error loading Facebook NLLB model or tokenizer: {e}")
180
+ return "Error loading translation model."
181
+ else:
182
+ return f"Unknown model type for {_MODEL_NAME}"
183
+
184
+ return f"Model and tokenizer set for {_readable_name}."
185
+
186
+
187
+ def chunk_text_by_tokens(text, tokenizer, max_tokens):
188
+ """Splits text into chunks based on token count."""
189
+ words = text.split()
190
+ chunks = []
191
+ current_chunk = []
192
+ for word in words:
193
+ trial_chunk = current_chunk + [word]
194
+ # Use add_special_tokens=False to get token count of just the words
195
+ num_tokens = len(tokenizer(" ".join(trial_chunk), add_special_tokens=False).input_ids)
196
+ if num_tokens > max_tokens:
197
+ if current_chunk:
198
+ chunks.append(" ".join(current_chunk))
199
+ current_chunk = [word]
200
+ else:
201
+ current_chunk = trial_chunk
202
+ if current_chunk:
203
+ chunks.append(" ".join(current_chunk))
204
+ return chunks
205
+
206
+
207
+ def translate_me(text, language_code):
208
+ """Translates the input text to the target language using the loaded model."""
209
+ global model, tokenizer, device, formatted_language_code
210
+
211
+ if model is None or tokenizer is None:
212
+ status = setModelAndTokenizer(language_code)
213
+ if "Error" in status or "not supported" in status:
214
+ print(status)
215
+ return f"Translation failed: {status}"
216
+
217
+ if text is None or text.strip() == "":
218
+ return "No text to translate."
219
+
220
+ try:
221
+ if language_code in ['ar', 'fr']:
222
+ inputs = tokenizer(text, return_tensors="pt", padding=True).to(device)
223
+ translated = model.generate(**inputs)
224
+ return tokenizer.decode(translated[0], skip_special_tokens=True)
225
+
226
+ elif language_code in ['ha','fa','ps']:
227
+ SAFE_CHUNK_SIZE = 900
228
+ tokenizer.src_lang = "eng_Latn" # English
229
+ bos_token_id = tokenizer.convert_tokens_to_ids([formatted_language_code])[0]
230
+ chunks = chunk_text_by_tokens(text, tokenizer, SAFE_CHUNK_SIZE)
231
+ translations = []
232
+ for chunk in chunks:
233
+ inputs = tokenizer(chunk, return_tensors="pt").to(device)
234
+ translated_tokens = model.generate(
235
+ **inputs,
236
+ forced_bos_token_id=bos_token_id,
237
+ max_length=512
238
+ )
239
+ translation = tokenizer.decode(translated_tokens[0], skip_special_tokens=True)
240
+ translations.append(translation)
241
+ return "\n".join(translations)
242
+ else:
243
+ return f"Translation not implemented for language code: {language_code}"
244
+
245
+ except Exception as e:
246
+ print(f"Error during translation: {e}")
247
+ return "Error during translation."
248
+
249
+
250
+ def say_it_api(text, _out_lang):
251
+ """
252
+ Converts text to speech using gTTS and saves it to a temporary file.
253
+ Returns the file path.
254
+ """
255
+ if text is None or text.strip() == "":
256
+ print("No text provided for gTTS speech generation.")
257
+ return None
258
+ try:
259
+ tts = gTTS(text=text, lang=_out_lang)
260
+ filename = "/tmp/gtts_audio.mp3"
261
+ tts.save(filename)
262
+ return filename
263
+ except Exception as e:
264
+ print(f"Error during gTTS speech generation: {e}")
265
+ return None
266
+
267
+ def speak_with_elevenlabs_api(text, language_code):
268
+ """
269
+ Converts text to speech using ElevenLabs API and saves it to a temporary file.
270
+ Returns the file path.
271
+ """
272
+ ELEVENLABS_API_KEY = os.environ.get('ELEVENLABS_API_KEY')
273
+ VOICE_ID = "EXAVITQu4vr4xnSDxMaL" # Rachel; see docs for voices
274
+
275
+ if not ELEVENLABS_API_KEY:
276
+ print("ElevenLabs API key not found in environment variables.")
277
+ return None
278
+
279
+ if text is None or text.strip() == "":
280
+ print("No text provided for ElevenLabs speech generation.")
281
+ return None
282
+
283
+ url = f"https://api.elevenlabs.io/v1/text-to-speech/{VOICE_ID}"
284
+ headers = {
285
+ "xi-api-key": ELEVENLABS_API_KEY,
286
+ "Content-Type": "application/json"
287
+ }
288
+ data = {
289
+ "text": text,
290
+ "model_id": "eleven_multilingual_v2",
291
+ "voice_settings": {
292
+ "stability": 0.5,
293
+ "similarity_boost": 0.5
294
+ }
295
+ }
296
+ try:
297
+ response = requests.post(url, headers=headers, json=data)
298
+ if response.status_code == 200:
299
+ filename = "/tmp/elevenlabs_audio.mp3"
300
+ with open(filename, 'wb') as f:
301
+ f.write(response.content)
302
+ return filename
303
+ else:
304
+ print(f"Error from ElevenLabs API: Status Code {response.status_code}, Response: {response.text}")
305
+ return None
306
+ except Exception as e:
307
+ print(f"Error calling ElevenLabs API: {e}")
308
+ return None
309
+
310
+
311
+ def speechRouter_api(text,language_code):
312
+ """
313
+ Routes text-to-speech requests based on language code and returns the audio file path.
314
+ """
315
+ if text is None or text.strip() == "":
316
+ return None # No text to speak
317
+
318
+ if language_code == 'ar':
319
+ return say_it_api(text,language_code)
320
+ elif language_code == 'fr':
321
+ return say_it_api(text,language_code)
322
+ elif language_code in ['ha', 'fa', 'ps']:
323
+ return speak_with_elevenlabs_api(text, language_code)
324
+ else:
325
+ print(f"Language code '{language_code}' not supported for speech generation.")
326
+ return None
327
+
328
+
329
+ def translate_and_speak_api_wrapper(video_id, out_lang):
330
+ """
331
+ Translates the given English text from a Youtube video transcript
332
+ to other languages and generates speech for the translated text.
333
+
334
+ Args:
335
+ video_id: The Youtube video ID to translate and speak.
336
+ out_lang: The language to translate to.
337
+
338
+ Returns:
339
+ A tuple containing:
340
+ - translated_text (str): The translated text.
341
+ - audio_file_path (str or None): The path to the generated audio file, or None if speech generation failed.
342
+ """
343
+ # Ensure model and tokenizer are loaded for the target language
344
+ model_status = setModelAndTokenizer(out_lang)
345
+ if "Error" in model_status or "not supported" in model_status:
346
+ return f"Translation failed: {model_status}", None
347
+
348
+ english_text = getEnglishTranscript(video_id)
349
+
350
+ if english_text == "":
351
+ return "No English transcript available to translate.", None
352
+
353
+ translated_text = ""
354
+ if out_lang == "ar":
355
+ translated_text = getArabicTranscript(video_id)
356
+ if translated_text.strip() == "": # If no direct Arabic transcript, translate English
357
+ print("No direct Arabic transcript found, translating from English.")
358
+ translated_text = translate_me(english_text,out_lang)
359
+ elif out_lang == "fr":
360
+ translated_text = getFrenchTranscript(video_id)
361
+ if translated_text.strip() == "": # If no direct French transcript, translate English
362
+ print("No direct French transcript found, translating from English.")
363
+ translated_text = translate_me(english_text,out_lang)
364
+ elif out_lang in ["ha", "fa", "ps"]:
365
+ translated_text = translate_me(english_text,out_lang)
366
+ else:
367
+ return f"Language code '{out_lang}' not supported for translation.", None
368
+
369
+ if translated_text is None or translated_text.strip() == "" or "Translation failed" in translated_text:
370
+ return f"Translation to {out_lang} failed.", None
371
+
372
+ # Generate speech using the API wrapper
373
+ audio_file_path = speechRouter_api(translated_text, out_lang)
374
+
375
+ return translated_text, audio_file_path
376
+
377
+ # This function will serve as the API endpoint for Gradio.
378
+ def translate_and_speak_api(video_id: str, language_code: str):
379
+ """
380
+ API endpoint to translate and speak YouTube video transcripts.
381
+ """
382
+ print(f"Received request for video ID: {video_id}, language: {language_code}")
383
+ translated_text, audio_file_path = translate_and_speak_api_wrapper(video_id, language_code)
384
+
385
+ # Return the translated text and the audio file path (or an empty string if None)
386
+ # Returning an empty string instead of None for the audio output might resolve
387
+ # the TypeError when autoplay is True.
388
+ return translated_text, audio_file_path if audio_file_path is not None else ""
389
+
390
+
391
+ # Define input components
392
+ video_id_input = gr.Textbox(label="YouTube Video ID")
393
+ language_dropdown = gr.Dropdown(
394
+ label="Target Language",
395
+ choices=['ar', 'fr', 'ha', 'fa', 'ps'], # Supported language codes
396
+ value='ar' # Default value
397
+ )
398
+
399
+ # Define output components
400
+ translated_text_output = gr.Textbox(label="Translated Text")
401
+ audio_output = gr.Audio(label="Translated Speech", autoplay=True)
402
+
403
+ # Combine components and the translate_and_speak_api function into a Gradio interface
404
+ demo = gr.Interface(
405
+ fn=translate_and_speak_api, # Use the API endpoint function
406
+ inputs=[video_id_input, language_dropdown], # Inputs match the API function arguments
407
+ outputs=[translated_text_output, audio_output], # Outputs match the API function return values
408
+ title="YouTube Translator and Speaker",
409
+ description="Enter a YouTube video ID and select a language to get the translated transcript and speech."
410
+ )
411
+
412
+ # ---- Launch Gradio ----
413
+
414
+ if __name__ == "__main__":
415
+ demo.launch()
gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ youtube-transcript-api
3
+ transformers
4
+ sacremoses
5
+ gTTS
6
+ requests
7
+ torch
8
+ sentencepiece
9
+ accelerate