divython commited on
Commit
66b0e4e
ยท
verified ยท
1 Parent(s): a5917cd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +258 -130
app.py CHANGED
@@ -3,8 +3,12 @@ import re
3
  import requests
4
  from transformers import pipeline, AutoTokenizer, AutoModelForSeq2SeqLM
5
  from youtube_transcript_api import YouTubeTranscriptApi
 
6
  import torch
7
  import gc
 
 
 
8
 
9
  # Optimize for HuggingFace Spaces - Use smaller models and efficient loading
10
  print("๐Ÿš€ Loading models for HuggingFace Spaces...")
@@ -13,72 +17,141 @@ print("๐Ÿš€ Loading models for HuggingFace Spaces...")
13
  @torch.no_grad()
14
  def load_summarizer():
15
  model_name = "facebook/bart-large-cnn"
16
- tokenizer = AutoTokenizer.from_pretrained(model_name)
17
- model = AutoModelForSeq2SeqLM.from_pretrained(model_name, torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32)
18
- return pipeline("summarization", model=model, tokenizer=tokenizer, device=0 if torch.cuda.is_available() else -1)
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  # Initialize summarizer
21
  summarizer = load_summarizer()
22
 
23
  def extract_video_id(url):
24
  """Extract video ID from various YouTube URL formats"""
 
 
 
 
 
 
25
  patterns = [
26
  r'(?:v=|\/)([0-9A-Za-z_-]{11}).*',
27
  r'(?:embed\/)([0-9A-Za-z_-]{11})',
28
  r'(?:v\/)([0-9A-Za-z_-]{11})',
29
- r'(?:youtu\.be\/)([0-9A-Za-z_-]{11})'
 
30
  ]
 
31
  for pattern in patterns:
32
  match = re.search(pattern, url)
33
  if match:
34
- return match.group(1)
 
 
 
35
  return None
36
 
37
- def get_youtube_transcript(video_id):
38
- """Get transcript using YouTube Transcript API - Most reliable for HF Spaces"""
39
  try:
40
- # Priority order for languages (Hindi, English variants)
41
- language_codes = ['hi', 'en', 'en-IN', 'en-US', 'en-GB']
42
-
43
- transcript_data = None
44
- used_language = None
45
-
46
- # Try each language
47
- for lang_code in language_codes:
48
- try:
49
- transcript_list = YouTubeTranscriptApi.get_transcript(video_id, languages=[lang_code])
50
- transcript_data = transcript_list
51
- used_language = lang_code
52
- break
53
- except:
54
- continue
55
-
56
- # If specific languages fail, try auto-generated
57
- if not transcript_data:
58
- try:
59
- transcript_list = YouTubeTranscriptApi.get_transcript(video_id)
60
- transcript_data = transcript_list
61
- used_language = "auto-detected"
62
- except Exception as e:
63
- return None, f"No transcript available: {str(e)}"
64
-
65
- # Process transcript
66
- if transcript_data:
67
- transcript_text = ' '.join([item['text'].replace('\n', ' ') for item in transcript_data])
68
- # Clean up common transcript artifacts
69
- transcript_text = re.sub(r'\[.*?\]', '', transcript_text) # Remove [Music], [Applause] etc
70
- transcript_text = re.sub(r'\s+', ' ', transcript_text).strip() # Clean whitespace
71
 
72
- return transcript_text, f"Transcript found in: {used_language}"
73
-
74
- return None, "No transcript data found"
75
-
76
- except Exception as e:
77
- return None, f"Transcript API Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
  def chunk_text_for_summarization(text, max_chunk_size=800):
80
  """Split text into chunks for summarization"""
81
- sentences = text.replace('เฅค', '.').split('.') # Handle Hindi sentences
 
 
 
 
82
  chunks = []
83
  current_chunk = ""
84
 
@@ -88,23 +161,26 @@ def chunk_text_for_summarization(text, max_chunk_size=800):
88
  continue
89
 
90
  # Check if adding this sentence would exceed limit
91
- if len(current_chunk) + len(sentence) + 1 < max_chunk_size:
92
  current_chunk += sentence + ". "
93
  else:
94
- if current_chunk:
95
  chunks.append(current_chunk.strip())
96
  current_chunk = sentence + ". "
97
 
98
  # Add the last chunk
99
- if current_chunk:
100
  chunks.append(current_chunk.strip())
101
 
102
- return chunks
103
 
104
  def summarize_text_optimized(text):
105
  """Optimized summarization for HuggingFace Spaces"""
 
 
 
106
  if not text or len(text.strip()) < 100:
107
- return "Text too short to summarize (minimum 100 characters required)"
108
 
109
  try:
110
  # Clean memory before processing
@@ -113,23 +189,24 @@ def summarize_text_optimized(text):
113
  gc.collect()
114
 
115
  # For very long texts, chunk them
116
- if len(text) > 1500:
117
- chunks = chunk_text_for_summarization(text, max_chunk_size=900)
118
  summaries = []
119
 
120
- # Process first 3 chunks to avoid timeout
121
- for i, chunk in enumerate(chunks[:3]):
122
  if len(chunk.strip()) < 50:
123
  continue
124
 
125
  try:
126
  summary = summarizer(
127
  chunk,
128
- max_length=120,
129
- min_length=30,
130
  do_sample=False,
131
- num_beams=2, # Reduced for speed
132
- length_penalty=1.0
 
133
  )[0]["summary_text"]
134
  summaries.append(summary)
135
  except Exception as chunk_error:
@@ -138,86 +215,108 @@ def summarize_text_optimized(text):
138
 
139
  if summaries:
140
  combined_summary = " ".join(summaries)
 
141
  # If combined summary is still too long, summarize it again
142
- if len(combined_summary) > 600:
143
  try:
144
  final_summary = summarizer(
145
  combined_summary,
146
  max_length=200,
147
- min_length=80,
148
  do_sample=False,
149
- num_beams=2
 
150
  )[0]["summary_text"]
151
  return final_summary
152
  except:
153
- return combined_summary
154
  return combined_summary
155
  else:
156
- return "Could not generate summary from chunks"
157
  else:
158
  # For shorter texts, direct summarization
 
 
 
 
159
  summary = summarizer(
160
  text,
161
- max_length=150,
162
- min_length=50,
163
  do_sample=False,
164
  num_beams=2,
165
- length_penalty=1.0
 
166
  )[0]["summary_text"]
167
  return summary
168
 
169
  except Exception as e:
170
- return f"Summarization error: {str(e)}"
171
 
172
- def process_youtube_video(url):
173
  """Main processing function optimized for HuggingFace Spaces"""
174
 
175
  # Input validation
176
  if not url or not url.strip():
177
- return "โŒ Please enter a YouTube URL", "", "No summary available"
 
 
178
 
179
  # Extract video ID
180
  video_id = extract_video_id(url.strip())
181
  if not video_id:
182
- return "โŒ Invalid YouTube URL format", "Please check the URL format", "No summary available"
 
 
183
 
184
- # Update progress
185
- progress_msg = "๐Ÿ” Extracting video transcript..."
186
 
187
  # Get transcript
188
- transcript, status = get_youtube_transcript(video_id)
189
 
190
  if not transcript:
191
  return (
192
  "โŒ Could not extract transcript",
193
- f"Status: {status}\n\nThis video might not have captions/subtitles available.",
194
- "Cannot generate summary without transcript"
 
 
 
 
195
  )
196
 
 
 
197
  # Generate summary
198
- progress_msg = "๐Ÿค– Generating AI summary..."
199
  summary = summarize_text_optimized(transcript)
200
 
 
 
201
  # Create video embed
202
  embed_html = f'''
203
- <div style="text-align: center;">
204
- <iframe width="560" height="315"
205
  src="https://www.youtube.com/embed/{video_id}"
206
  frameborder="0"
207
  allowfullscreen
208
- style="max-width: 100%; border-radius: 10px;">
209
  </iframe>
210
  </div>
211
  '''
212
 
213
  # Format transcript info
214
- transcript_info = f"""๐Ÿ“Š Processing Status: โœ… Success
215
- ๐ŸŽฏ Method: YouTube Transcript API
216
- ๐ŸŒ Language: {status}
217
- ๐Ÿ“ Transcript Length: {len(transcript)} characters
218
- ๐Ÿ“„ Word Count: ~{len(transcript.split())} words
 
 
 
 
 
219
 
220
- ๐Ÿ“‹ Full Transcript:
221
  {transcript}"""
222
 
223
  return embed_html, transcript_info, summary
@@ -225,106 +324,134 @@ def process_youtube_video(url):
225
  # Custom CSS for better UI
226
  custom_css = """
227
  #component-0 {
228
- max-width: 900px;
229
  margin: auto;
230
  }
231
  .gradio-container {
232
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
233
  }
 
 
 
234
  """
235
 
236
  # Create Gradio Interface optimized for HuggingFace Spaces
237
- with gr.Blocks(css=custom_css, title="YouTube Video Summarizer", theme=gr.themes.Soft()) as demo:
238
  gr.HTML("""
239
- <div style="text-align: center; padding: 20px;">
240
- <h1>๐ŸŽ“ YouTube Video Summarizer</h1>
241
- <p style="font-size: 18px; color: #666;">
242
  AI-powered summarization for Hindi, Hinglish & English videos
243
  </p>
244
- <p style="color: #888;">
245
- Optimized for HuggingFace Spaces โ€ข Uses YouTube Transcript API
246
  </p>
247
  </div>
248
  """)
249
 
250
  with gr.Row():
251
- with gr.Column(scale=2):
252
  url_input = gr.Textbox(
253
  label="๐Ÿ“บ YouTube URL",
254
- placeholder="https://www.youtube.com/watch?v=...",
255
  lines=1,
256
- info="Paste any YouTube video URL here"
257
  )
258
 
259
  with gr.Column(scale=1):
260
  submit_btn = gr.Button(
261
- "๐Ÿš€ Summarize Video",
262
  variant="primary",
263
  size="lg"
264
  )
265
 
 
 
 
266
  # Results section
267
  with gr.Row():
268
- with gr.Column():
269
  video_embed = gr.HTML(label="๐Ÿ“บ Video Player")
270
 
271
- with gr.Column():
272
  summary_output = gr.Textbox(
273
  label="๐Ÿ“‹ AI Summary",
274
- lines=8,
275
- max_lines=12,
276
- info="AI-generated summary of the video content"
 
277
  )
278
 
279
  # Expandable transcript section
280
- with gr.Accordion("๐Ÿ“ Full Transcript & Details", open=False):
281
  transcript_output = gr.Textbox(
282
- label="Complete Transcript",
283
- lines=15,
284
- max_lines=25,
285
- info="Full video transcript with processing details"
 
286
  )
287
 
288
  # Examples section
289
- gr.HTML("<h3 style='margin-top: 30px;'>๐ŸŽฏ Try these examples:</h3>")
290
 
 
291
  gr.Examples(
292
  examples=[
293
- ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
294
- ["https://youtu.be/dQw4w9WgXcQ"],
 
295
  ],
296
  inputs=url_input,
297
- label="Sample URLs"
298
  )
299
 
300
  # Info section
301
- with gr.Accordion("โ„น๏ธ How it works", open=False):
302
  gr.Markdown("""
303
  ### ๐Ÿ”ง How this tool works:
304
 
305
- 1. **Extract Video ID**: Parses the YouTube URL to get the video identifier
306
- 2. **Fetch Transcript**: Uses YouTube Transcript API to get captions/subtitles
307
- 3. **AI Summarization**: Processes text through BART model for intelligent summarization
308
- 4. **Multi-language Support**: Handles Hindi, Hinglish, and English content
 
309
 
310
  ### ๐Ÿ“‹ Supported Languages:
311
  - ๐Ÿ‡ฎ๐Ÿ‡ณ **Hindi**: Full support for Hindi captions
312
- - ๐ŸŒ **Hinglish**: Mixed Hindi-English content
313
  - ๐Ÿ‡บ๐Ÿ‡ธ **English**: All English variants
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
 
315
- ### โšก Optimizations for HuggingFace Spaces:
316
- - Efficient model loading with memory management
317
- - Chunked processing for long videos
318
- - GPU acceleration when available
319
- - Automatic text cleanup and formatting
320
 
321
- ### โš ๏ธ Limitations:
322
- - Requires videos to have captions/subtitles
323
- - Processing time depends on transcript length
324
- - Very long videos are chunked to prevent timeouts
 
325
  """)
326
 
327
- # Event handlers
328
  submit_btn.click(
329
  fn=process_youtube_video,
330
  inputs=[url_input],
@@ -339,11 +466,12 @@ with gr.Blocks(css=custom_css, title="YouTube Video Summarizer", theme=gr.themes
339
 
340
  # Launch configuration for HuggingFace Spaces
341
  if __name__ == "__main__":
342
- demo.queue(max_size=10) # Limit queue size for stability
343
  demo.launch(
344
  server_name="0.0.0.0",
345
  server_port=7860,
346
- share=False, # Don't need share link in HF Spaces
347
- debug=False, # Disable debug in production
348
- show_error=True
 
349
  )
 
3
  import requests
4
  from transformers import pipeline, AutoTokenizer, AutoModelForSeq2SeqLM
5
  from youtube_transcript_api import YouTubeTranscriptApi
6
+ from youtube_transcript_api.formatters import TextFormatter
7
  import torch
8
  import gc
9
+ import time
10
+ from urllib.parse import urlparse, parse_qs
11
+ import json
12
 
13
  # Optimize for HuggingFace Spaces - Use smaller models and efficient loading
14
  print("๐Ÿš€ Loading models for HuggingFace Spaces...")
 
17
  @torch.no_grad()
18
  def load_summarizer():
19
  model_name = "facebook/bart-large-cnn"
20
+ try:
21
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
22
+ model = AutoModelForSeq2SeqLM.from_pretrained(
23
+ model_name,
24
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
25
+ )
26
+ return pipeline("summarization", model=model, tokenizer=tokenizer,
27
+ device=0 if torch.cuda.is_available() else -1)
28
+ except Exception as e:
29
+ print(f"Error loading summarizer: {e}")
30
+ # Fallback to a smaller model if BART fails
31
+ try:
32
+ return pipeline("summarization", model="sshleifer/distilbart-cnn-12-6",
33
+ device=0 if torch.cuda.is_available() else -1)
34
+ except:
35
+ return None
36
 
37
  # Initialize summarizer
38
  summarizer = load_summarizer()
39
 
40
  def extract_video_id(url):
41
  """Extract video ID from various YouTube URL formats"""
42
+ if not url:
43
+ return None
44
+
45
+ # Clean the URL
46
+ url = url.strip()
47
+
48
  patterns = [
49
  r'(?:v=|\/)([0-9A-Za-z_-]{11}).*',
50
  r'(?:embed\/)([0-9A-Za-z_-]{11})',
51
  r'(?:v\/)([0-9A-Za-z_-]{11})',
52
+ r'(?:youtu\.be\/)([0-9A-Za-z_-]{11})',
53
+ r'(?:watch\?v=)([0-9A-Za-z_-]{11})'
54
  ]
55
+
56
  for pattern in patterns:
57
  match = re.search(pattern, url)
58
  if match:
59
+ video_id = match.group(1)
60
+ # Validate video ID length
61
+ if len(video_id) == 11:
62
+ return video_id
63
  return None
64
 
65
+ def get_video_info(video_id):
66
+ """Get basic video information"""
67
  try:
68
+ # This is a simple way to check if video exists
69
+ # In production, you might want to use YouTube Data API
70
+ return f"https://www.youtube.com/watch?v={video_id}"
71
+ except:
72
+ return None
73
+
74
+ def get_youtube_transcript_with_retry(video_id, max_retries=3):
75
+ """Get transcript with retry mechanism and better error handling"""
76
+
77
+ if not video_id:
78
+ return None, "Invalid video ID"
79
+
80
+ # Language priority order
81
+ language_codes = ['hi', 'en', 'en-IN', 'en-US', 'en-GB', 'auto']
82
+
83
+ for attempt in range(max_retries):
84
+ try:
85
+ transcript_data = None
86
+ used_language = None
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
+ # Try each language
89
+ for lang_code in language_codes:
90
+ try:
91
+ if lang_code == 'auto':
92
+ # Try auto-generated as last resort
93
+ transcript_list = YouTubeTranscriptApi.get_transcript(video_id)
94
+ else:
95
+ transcript_list = YouTubeTranscriptApi.get_transcript(video_id, languages=[lang_code])
96
+
97
+ transcript_data = transcript_list
98
+ used_language = lang_code
99
+ break
100
+ except Exception as lang_error:
101
+ continue
102
+
103
+ # Process transcript if found
104
+ if transcript_data:
105
+ formatter = TextFormatter()
106
+ transcript_text = formatter.format_transcript(transcript_data)
107
+
108
+ # Clean up the transcript
109
+ transcript_text = re.sub(r'\[.*?\]', '', transcript_text) # Remove [Music], [Applause] etc
110
+ transcript_text = re.sub(r'\s+', ' ', transcript_text).strip() # Clean whitespace
111
+ transcript_text = re.sub(r'\.{2,}', '.', transcript_text) # Fix multiple dots
112
+
113
+ if len(transcript_text) < 50:
114
+ return None, "Transcript too short or empty"
115
+
116
+ return transcript_text, f"Success - Language: {used_language}"
117
+
118
+ # If no transcript found, wait before retry
119
+ if attempt < max_retries - 1:
120
+ time.sleep(2 ** attempt) # Exponential backoff
121
+
122
+ except Exception as e:
123
+ error_msg = str(e).lower()
124
+
125
+ # Handle specific YouTube API errors
126
+ if "transcript disabled" in error_msg:
127
+ return None, "โŒ Transcripts are disabled for this video"
128
+ elif "not available" in error_msg:
129
+ return None, "โŒ No transcript available for this video"
130
+ elif "video unavailable" in error_msg:
131
+ return None, "โŒ Video is unavailable or private"
132
+ elif "quota exceeded" in error_msg:
133
+ return None, "โŒ API quota exceeded, please try again later"
134
+ elif any(block_term in error_msg for block_term in ["ip", "block", "banned", "rate limit"]):
135
+ if attempt < max_retries - 1:
136
+ time.sleep(5 * (attempt + 1)) # Longer wait for IP blocks
137
+ continue
138
+ else:
139
+ return None, "โŒ IP blocked by YouTube. Try using a VPN or proxy, or try again later"
140
+ else:
141
+ print(f"Attempt {attempt + 1} failed: {e}")
142
+ if attempt < max_retries - 1:
143
+ time.sleep(2 ** attempt)
144
+ continue
145
+
146
+ return None, f"โŒ Failed to get transcript after {max_retries} attempts"
147
 
148
  def chunk_text_for_summarization(text, max_chunk_size=800):
149
  """Split text into chunks for summarization"""
150
+ if not text:
151
+ return []
152
+
153
+ # Handle different sentence endings (English and Hindi)
154
+ sentences = re.split(r'[.เฅค!?]+', text)
155
  chunks = []
156
  current_chunk = ""
157
 
 
161
  continue
162
 
163
  # Check if adding this sentence would exceed limit
164
+ if len(current_chunk) + len(sentence) + 2 < max_chunk_size:
165
  current_chunk += sentence + ". "
166
  else:
167
+ if current_chunk.strip():
168
  chunks.append(current_chunk.strip())
169
  current_chunk = sentence + ". "
170
 
171
  # Add the last chunk
172
+ if current_chunk.strip():
173
  chunks.append(current_chunk.strip())
174
 
175
+ return [chunk for chunk in chunks if len(chunk.strip()) > 20]
176
 
177
  def summarize_text_optimized(text):
178
  """Optimized summarization for HuggingFace Spaces"""
179
+ if not summarizer:
180
+ return "โŒ Summarization model not available"
181
+
182
  if not text or len(text.strip()) < 100:
183
+ return "โŒ Text too short to summarize (minimum 100 characters required)"
184
 
185
  try:
186
  # Clean memory before processing
 
189
  gc.collect()
190
 
191
  # For very long texts, chunk them
192
+ if len(text) > 1200:
193
+ chunks = chunk_text_for_summarization(text, max_chunk_size=800)
194
  summaries = []
195
 
196
+ # Process chunks (limit to first 4 to avoid timeout)
197
+ for i, chunk in enumerate(chunks[:4]):
198
  if len(chunk.strip()) < 50:
199
  continue
200
 
201
  try:
202
  summary = summarizer(
203
  chunk,
204
+ max_length=min(120, len(chunk.split()) // 3 + 20),
205
+ min_length=20,
206
  do_sample=False,
207
+ num_beams=2,
208
+ length_penalty=1.0,
209
+ early_stopping=True
210
  )[0]["summary_text"]
211
  summaries.append(summary)
212
  except Exception as chunk_error:
 
215
 
216
  if summaries:
217
  combined_summary = " ".join(summaries)
218
+
219
  # If combined summary is still too long, summarize it again
220
+ if len(combined_summary) > 500:
221
  try:
222
  final_summary = summarizer(
223
  combined_summary,
224
  max_length=200,
225
+ min_length=60,
226
  do_sample=False,
227
+ num_beams=2,
228
+ early_stopping=True
229
  )[0]["summary_text"]
230
  return final_summary
231
  except:
232
+ return combined_summary[:500] + "..."
233
  return combined_summary
234
  else:
235
+ return "โŒ Could not generate summary from the provided text"
236
  else:
237
  # For shorter texts, direct summarization
238
+ word_count = len(text.split())
239
+ max_length = min(150, word_count // 2 + 30)
240
+ min_length = min(30, word_count // 4)
241
+
242
  summary = summarizer(
243
  text,
244
+ max_length=max_length,
245
+ min_length=min_length,
246
  do_sample=False,
247
  num_beams=2,
248
+ length_penalty=1.0,
249
+ early_stopping=True
250
  )[0]["summary_text"]
251
  return summary
252
 
253
  except Exception as e:
254
+ return f"โŒ Summarization error: {str(e)}"
255
 
256
+ def process_youtube_video(url, progress=gr.Progress()):
257
  """Main processing function optimized for HuggingFace Spaces"""
258
 
259
  # Input validation
260
  if not url or not url.strip():
261
+ return "โŒ Please enter a YouTube URL", "", "โŒ No summary available - URL required"
262
+
263
+ progress(0.1, desc="Validating URL...")
264
 
265
  # Extract video ID
266
  video_id = extract_video_id(url.strip())
267
  if not video_id:
268
+ return ("โŒ Invalid YouTube URL format",
269
+ "Please use a valid YouTube URL like:\n- https://www.youtube.com/watch?v=VIDEO_ID\n- https://youtu.be/VIDEO_ID",
270
+ "โŒ Cannot generate summary without valid URL")
271
 
272
+ progress(0.2, desc="Extracting video transcript...")
 
273
 
274
  # Get transcript
275
+ transcript, status = get_youtube_transcript_with_retry(video_id)
276
 
277
  if not transcript:
278
  return (
279
  "โŒ Could not extract transcript",
280
+ f"Status: {status}\n\n๐Ÿ’ก Troubleshooting tips:\n"
281
+ "โ€ข Check if the video has captions/subtitles enabled\n"
282
+ "โ€ข Try a different video\n"
283
+ "โ€ข If using HuggingFace Spaces, try again later due to IP restrictions\n"
284
+ "โ€ข Consider using a VPN if the issue persists",
285
+ "โŒ Cannot generate summary without transcript"
286
  )
287
 
288
+ progress(0.7, desc="Generating AI summary...")
289
+
290
  # Generate summary
 
291
  summary = summarize_text_optimized(transcript)
292
 
293
+ progress(1.0, desc="Complete!")
294
+
295
  # Create video embed
296
  embed_html = f'''
297
+ <div style="text-align: center; margin: 10px 0;">
298
+ <iframe width="100%" height="315"
299
  src="https://www.youtube.com/embed/{video_id}"
300
  frameborder="0"
301
  allowfullscreen
302
+ style="max-width: 560px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
303
  </iframe>
304
  </div>
305
  '''
306
 
307
  # Format transcript info
308
+ word_count = len(transcript.split())
309
+ char_count = len(transcript)
310
+
311
+ transcript_info = f"""โœ… **Processing Status**: Success
312
+ ๐ŸŽฏ **Method**: YouTube Transcript API
313
+ ๐ŸŒ **Language**: {status}
314
+ ๐Ÿ“Š **Statistics**:
315
+ โ€ข Characters: {char_count:,}
316
+ โ€ข Words: ~{word_count:,}
317
+ โ€ข Estimated reading time: ~{word_count//200 + 1} minutes
318
 
319
+ ๐Ÿ“‹ **Full Transcript**:
320
  {transcript}"""
321
 
322
  return embed_html, transcript_info, summary
 
324
  # Custom CSS for better UI
325
  custom_css = """
326
  #component-0 {
327
+ max-width: 1000px;
328
  margin: auto;
329
  }
330
  .gradio-container {
331
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
332
  }
333
+ .progress-bar {
334
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
335
+ }
336
  """
337
 
338
  # Create Gradio Interface optimized for HuggingFace Spaces
339
+ with gr.Blocks(css=custom_css, title="YouTube Video Summarizer AI", theme=gr.themes.Soft()) as demo:
340
  gr.HTML("""
341
+ <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 15px; margin-bottom: 20px; color: white;">
342
+ <h1 style="margin: 0; font-size: 2.5em;">๐ŸŽ“ YouTube Video Summarizer AI</h1>
343
+ <p style="font-size: 18px; margin: 10px 0; opacity: 0.9;">
344
  AI-powered summarization for Hindi, Hinglish & English videos
345
  </p>
346
+ <p style="opacity: 0.8; margin: 0;">
347
+ โšก Fast โ€ข ๐ŸŽฏ Accurate โ€ข ๐ŸŒ Multi-language Support
348
  </p>
349
  </div>
350
  """)
351
 
352
  with gr.Row():
353
+ with gr.Column(scale=3):
354
  url_input = gr.Textbox(
355
  label="๐Ÿ“บ YouTube URL",
356
+ placeholder="https://www.youtube.com/watch?v=dQw4w9WgXcQ",
357
  lines=1,
358
+ info="Paste any YouTube video URL here (must have captions/subtitles)"
359
  )
360
 
361
  with gr.Column(scale=1):
362
  submit_btn = gr.Button(
363
+ "๐Ÿš€ Analyze Video",
364
  variant="primary",
365
  size="lg"
366
  )
367
 
368
+ # Status indicator
369
+ status_text = gr.HTML("")
370
+
371
  # Results section
372
  with gr.Row():
373
+ with gr.Column(scale=1):
374
  video_embed = gr.HTML(label="๐Ÿ“บ Video Player")
375
 
376
+ with gr.Column(scale=1):
377
  summary_output = gr.Textbox(
378
  label="๐Ÿ“‹ AI Summary",
379
+ lines=12,
380
+ max_lines=15,
381
+ info="AI-generated summary of the video content",
382
+ show_copy_button=True
383
  )
384
 
385
  # Expandable transcript section
386
+ with gr.Accordion("๐Ÿ“ Full Transcript & Processing Details", open=False):
387
  transcript_output = gr.Textbox(
388
+ label="Complete Transcript with Metadata",
389
+ lines=20,
390
+ max_lines=30,
391
+ info="Full video transcript with processing details",
392
+ show_copy_button=True
393
  )
394
 
395
  # Examples section
396
+ gr.HTML("<h3 style='margin-top: 30px; text-align: center;'>๐ŸŽฏ Try these examples:</h3>")
397
 
398
+ # Note: Using placeholder examples - replace with actual working video IDs
399
  gr.Examples(
400
  examples=[
401
+ ["https://www.youtube.com/watch?v=kJQP7kiw5Fk"], # TED Talk example
402
+ ["https://youtu.be/9bZkp7q19f0"], # Educational content
403
+ ["https://www.youtube.com/watch?v=aircAruvnKk"], # Popular educational channel
404
  ],
405
  inputs=url_input,
406
+ label="Sample URLs (Educational Content)"
407
  )
408
 
409
  # Info section
410
+ with gr.Accordion("โ„น๏ธ How it works & Troubleshooting", open=False):
411
  gr.Markdown("""
412
  ### ๐Ÿ”ง How this tool works:
413
 
414
+ 1. **๐ŸŽฏ URL Parsing**: Extracts video ID from various YouTube URL formats
415
+ 2. **๐Ÿ“ Transcript Extraction**: Uses YouTube Transcript API with retry logic
416
+ 3. **๐Ÿค– AI Summarization**: Processes text through BART/DistilBART models
417
+ 4. **๐ŸŒ Multi-language Support**: Handles Hindi, Hinglish, and English content
418
+ 5. **โšก Smart Processing**: Chunks long videos and optimizes for performance
419
 
420
  ### ๐Ÿ“‹ Supported Languages:
421
  - ๐Ÿ‡ฎ๐Ÿ‡ณ **Hindi**: Full support for Hindi captions
422
+ - ๐ŸŒ **Hinglish**: Mixed Hindi-English content
423
  - ๐Ÿ‡บ๐Ÿ‡ธ **English**: All English variants
424
+ - ๐Ÿ”„ **Auto-generated**: Automatic language detection
425
+
426
+ ### โš ๏ธ Known Limitations & Solutions:
427
+
428
+ **IP Blocking Issues:**
429
+ - YouTube blocks many cloud provider IPs (HuggingFace Spaces, AWS, etc.)
430
+ - **Solution**: Try again later, use VPN, or run locally
431
+
432
+ **Video Requirements:**
433
+ - Video must have captions/subtitles (auto-generated or manual)
434
+ - Video must be public (not private or unlisted)
435
+
436
+ **Performance Optimizations:**
437
+ - Long videos are automatically chunked to prevent timeouts
438
+ - Memory management for stable processing
439
+ - Fallback to smaller models if needed
440
 
441
+ ### ๐Ÿ› ๏ธ Troubleshooting:
442
+ - **"No transcript available"**: Video lacks captions - try another video
443
+ - **"IP blocked"**: Common on cloud platforms - try VPN or local setup
444
+ - **"Video unavailable"**: Check if video is public and exists
445
+ - **Slow processing**: Normal for long videos - please wait
446
 
447
+ ### ๐Ÿ’ก Tips for Best Results:
448
+ - Use videos with clear speech and good audio quality
449
+ - Educational/tutorial videos often have better transcripts
450
+ - Shorter videos (< 20 minutes) process faster
451
+ - Popular channels often have better auto-generated captions
452
  """)
453
 
454
+ # Event handlers with progress tracking
455
  submit_btn.click(
456
  fn=process_youtube_video,
457
  inputs=[url_input],
 
466
 
467
  # Launch configuration for HuggingFace Spaces
468
  if __name__ == "__main__":
469
+ demo.queue(max_size=5, default_concurrency_limit=2) # Limit for stability
470
  demo.launch(
471
  server_name="0.0.0.0",
472
  server_port=7860,
473
+ share=False,
474
+ debug=False,
475
+ show_error=True,
476
+ max_threads=2 # Limit threads for better memory management
477
  )