Dhruv-Ty commited on
Commit
931d313
·
verified ·
1 Parent(s): bd4a2f0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -21
app.py CHANGED
@@ -29,8 +29,78 @@ def is_valid_url(url):
29
  return True
30
  return False
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  def download_video(url, progress=gr.Progress()):
33
- """Download video from URL using yt-dlp"""
34
  if not is_valid_url(url):
35
  raise gr.Error("Please enter a valid YouTube, Instagram, TikTok, or X video URL")
36
 
@@ -40,19 +110,20 @@ def download_video(url, progress=gr.Progress()):
40
  temp_video = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
41
  temp_video.close()
42
 
43
- # yt-dlp options optimized for HF Spaces
44
  ydl_opts = {
45
  'outtmpl': temp_video.name,
46
- 'format': 'best[filesize<100M]/worst[filesize<100M]/best',
47
  'quiet': True,
48
  'no_warnings': True,
49
  'nooverwrites': False,
50
  'user_agent': 'Mozilla/5.0 (compatible; GradioApp/1.0)',
51
- 'retries': 2,
52
- 'fragment_retries': 2,
53
- 'extractor_retries': 2,
54
- 'socket_timeout': 30,
55
  'nocheckcertificate': True,
 
56
  }
57
 
58
  progress(0.3, desc="Downloading video...")
@@ -65,7 +136,7 @@ def download_video(url, progress=gr.Progress()):
65
  if os.path.exists(temp_video.name) and os.path.getsize(temp_video.name) > 0:
66
  file_size_mb = os.path.getsize(temp_video.name) / (1024 * 1024)
67
 
68
- if file_size_mb > 100:
69
  os.unlink(temp_video.name)
70
  raise gr.Error(f"Video too large ({file_size_mb:.1f}MB). Please use a smaller video.")
71
 
@@ -83,12 +154,20 @@ def download_video(url, progress=gr.Progress()):
83
  pass
84
 
85
  error_msg = str(e)
86
- if "403" in error_msg or "Forbidden" in error_msg:
87
- raise gr.Error("Video download was blocked. Try a different video or use a shorter one.")
88
- elif "404" in error_msg:
89
- raise gr.Error("Video not found. Please check the URL.")
 
 
 
 
 
 
90
  else:
91
- raise gr.Error(f"Download failed: {error_msg}")
 
 
92
 
93
  def analyze_video_with_ai(video_path, query, progress=gr.Progress()):
94
  """Analyze video using Google Gemini AI"""
@@ -146,23 +225,41 @@ def analyze_video_with_ai(video_path, query, progress=gr.Progress()):
146
  pass
147
 
148
  def process_video_and_chat(url, query):
149
- """Main function to download video and get AI response"""
150
  if not url.strip():
151
  raise gr.Error("Please enter a video URL")
152
 
153
  if not query.strip():
154
  raise gr.Error("Please enter a question about the video")
155
 
156
- # Download video
157
  progress = gr.Progress()
158
  progress(0.0, desc="Starting...")
159
 
160
- video_path = download_video(url, progress)
161
-
162
- # Analyze with AI
163
- response = analyze_video_with_ai(video_path, query, progress)
164
-
165
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
  # Create Gradio interface
168
  def create_interface():
@@ -191,6 +288,10 @@ def create_interface():
191
  <div class="header">
192
  <h1>🎥 The Plug - AI Video Analyzer</h1>
193
  <p>Analyze videos from YouTube, Instagram, TikTok, and X with AI</p>
 
 
 
 
194
  </div>
195
  """)
196
 
 
29
  return True
30
  return False
31
 
32
+ def get_video_info(url):
33
+ """Get video information without downloading"""
34
+ try:
35
+ # Extract video ID for YouTube
36
+ if 'youtube.com' in url or 'youtu.be' in url:
37
+ video_id = None
38
+ if 'youtu.be/' in url:
39
+ video_id = url.split('youtu.be/')[-1].split('?')[0]
40
+ elif 'watch?v=' in url:
41
+ video_id = url.split('watch?v=')[-1].split('&')[0]
42
+
43
+ if video_id:
44
+ # Use YouTube oEmbed API (no key required, often works better)
45
+ import requests
46
+ oembed_url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={video_id}&format=json"
47
+ response = requests.get(oembed_url, timeout=10)
48
+ if response.status_code == 200:
49
+ data = response.json()
50
+ return {
51
+ 'title': data.get('title', 'Unknown Video'),
52
+ 'author': data.get('author_name', 'Unknown Author'),
53
+ 'thumbnail': data.get('thumbnail_url', ''),
54
+ }
55
+ except Exception as e:
56
+ print(f"Could not get video info: {e}")
57
+
58
+ return None
59
+
60
+ def analyze_video_from_url(url, query):
61
+ """Analyze video based on URL and metadata instead of downloading"""
62
+ # Get video information
63
+ video_info = get_video_info(url)
64
+
65
+ # Create context from URL and available info
66
+ context = f"Video URL: {url}\n"
67
+ if video_info:
68
+ context += f"Title: {video_info['title']}\n"
69
+ context += f"Author: {video_info['author']}\n"
70
+
71
+ # Generate AI response based on URL and context
72
+ try:
73
+ model = genai.GenerativeModel('gemini-2.0-flash-exp')
74
+
75
+ prompt = f"""
76
+ I have a video with the following information:
77
+ {context}
78
+
79
+ User question: {query}
80
+
81
+ Based on the video URL and available metadata, please provide helpful analysis and insights.
82
+ Since I cannot directly access the video content, please:
83
+
84
+ 1. Analyze what type of content this might be based on the URL and title
85
+ 2. Provide general guidance about analyzing this type of video
86
+ 3. Suggest what insights could typically be extracted
87
+ 4. Give relevant advice based on the platform (YouTube, Instagram, etc.)
88
+
89
+ Be helpful and informative while acknowledging the limitations of not having direct video access.
90
+ If this appears to be a specific type of content (tutorial, entertainment, news, etc.),
91
+ provide relevant analysis frameworks and questions that would be useful.
92
+
93
+ Be conversational and engaging.
94
+ """
95
+
96
+ response = model.generate_content(prompt)
97
+ return response.text
98
+
99
+ except Exception as e:
100
+ raise gr.Error(f"AI analysis failed: {str(e)}")
101
+
102
  def download_video(url, progress=gr.Progress()):
103
+ """Download video from URL using yt-dlp with better error handling"""
104
  if not is_valid_url(url):
105
  raise gr.Error("Please enter a valid YouTube, Instagram, TikTok, or X video URL")
106
 
 
110
  temp_video = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
111
  temp_video.close()
112
 
113
+ # yt-dlp options optimized for HF Spaces with better network handling
114
  ydl_opts = {
115
  'outtmpl': temp_video.name,
116
+ 'format': 'best[filesize<50M]/worst[filesize<50M]/best', # Smaller files for HF
117
  'quiet': True,
118
  'no_warnings': True,
119
  'nooverwrites': False,
120
  'user_agent': 'Mozilla/5.0 (compatible; GradioApp/1.0)',
121
+ 'retries': 1, # Reduced for HF Spaces
122
+ 'fragment_retries': 1,
123
+ 'extractor_retries': 1,
124
+ 'socket_timeout': 15, # Shorter timeout
125
  'nocheckcertificate': True,
126
+ 'prefer_insecure': True, # Sometimes helps with network issues
127
  }
128
 
129
  progress(0.3, desc="Downloading video...")
 
136
  if os.path.exists(temp_video.name) and os.path.getsize(temp_video.name) > 0:
137
  file_size_mb = os.path.getsize(temp_video.name) / (1024 * 1024)
138
 
139
+ if file_size_mb > 50: # Smaller limit for HF
140
  os.unlink(temp_video.name)
141
  raise gr.Error(f"Video too large ({file_size_mb:.1f}MB). Please use a smaller video.")
142
 
 
154
  pass
155
 
156
  error_msg = str(e)
157
+
158
+ # Handle specific network errors common in HF Spaces
159
+ if "Failed to resolve" in error_msg or "No address associated with hostname" in error_msg:
160
+ raise gr.Error("🌐 Network connectivity issue. Hugging Face Spaces may have restricted access to this platform. Try a different video or platform.")
161
+ elif "403" in error_msg or "Forbidden" in error_msg:
162
+ raise gr.Error("🚫 Video download was blocked by the platform. Try a different video.")
163
+ elif "404" in error_msg or "not found" in error_msg.lower():
164
+ raise gr.Error("📹 Video not found. Please check the URL.")
165
+ elif "timeout" in error_msg.lower():
166
+ raise gr.Error("⏱️ Download timed out. Try a shorter video.")
167
  else:
168
+ # For network errors, fall back to URL-based analysis
169
+ print(f"Download failed, falling back to URL analysis: {error_msg}")
170
+ raise Exception("download_failed") # Special exception for fallback
171
 
172
  def analyze_video_with_ai(video_path, query, progress=gr.Progress()):
173
  """Analyze video using Google Gemini AI"""
 
225
  pass
226
 
227
  def process_video_and_chat(url, query):
228
+ """Main function to download video and get AI response with fallback"""
229
  if not url.strip():
230
  raise gr.Error("Please enter a video URL")
231
 
232
  if not query.strip():
233
  raise gr.Error("Please enter a question about the video")
234
 
 
235
  progress = gr.Progress()
236
  progress(0.0, desc="Starting...")
237
 
238
+ try:
239
+ # Try to download video first
240
+ video_path = download_video(url, progress)
241
+
242
+ # Analyze with AI using actual video
243
+ response = analyze_video_with_ai(video_path, query, progress)
244
+
245
+ return response
246
+
247
+ except Exception as e:
248
+ # If download fails due to network issues, fall back to URL-based analysis
249
+ if str(e) == "download_failed" or "Network connectivity" in str(e) or "Failed to resolve" in str(e):
250
+ progress(0.5, desc="Switching to URL-based analysis...")
251
+
252
+ # Add a notice about the fallback
253
+ fallback_notice = "🔄 **Note**: Direct video download failed due to network restrictions, so I'm providing analysis based on the video URL and metadata.\n\n"
254
+
255
+ try:
256
+ response = analyze_video_from_url(url, query)
257
+ return fallback_notice + response
258
+ except Exception as fallback_error:
259
+ raise gr.Error(f"Both video download and URL analysis failed: {str(fallback_error)}")
260
+ else:
261
+ # Re-raise the original error if it's not a network issue
262
+ raise e
263
 
264
  # Create Gradio interface
265
  def create_interface():
 
288
  <div class="header">
289
  <h1>🎥 The Plug - AI Video Analyzer</h1>
290
  <p>Analyze videos from YouTube, Instagram, TikTok, and X with AI</p>
291
+ <div style="background: #f0f0f0; padding: 10px; border-radius: 8px; margin: 10px 0;">
292
+ <small><strong>🔄 Smart Fallback:</strong> If video download fails due to network restrictions,
293
+ the app will analyze based on video metadata and URL instead.</small>
294
+ </div>
295
  </div>
296
  """)
297