stevafernandes commited on
Commit
2277b76
Β·
verified Β·
1 Parent(s): 2a7b7da

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +181 -79
app.py CHANGED
@@ -39,43 +39,61 @@ class VideoProcessor:
39
  return f"Error generating response: {str(e)}"
40
 
41
  # Initialize session state properly
42
- if "messages" not in st.session_state:
43
- st.session_state.messages = []
44
- if "video_processor" not in st.session_state:
45
- st.session_state.video_processor = None
46
- if "video_file" not in st.session_state:
47
- st.session_state.video_file = None
48
- if "video_name" not in st.session_state:
49
- st.session_state.video_name = None
50
- if "api_key_validated" not in st.session_state:
51
- st.session_state.api_key_validated = False
 
 
 
52
 
53
  # Main app function
54
  def main():
55
- st.set_page_config(page_title="Video Retrieval-Augmented Generation", page_icon="", layout="wide")
56
- st.header("Video Retrieval-Augmented Generation - Gemini 2.0")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  st.markdown("---")
58
 
59
  # Step 1: API Key input
60
- st.subheader("Step 1: Enter Your API Key")
61
 
62
  # Check for environment variable first
63
  env_api_key = os.environ.get("GOOGLE_API_KEY", "")
 
64
 
65
  if env_api_key:
66
- st.info("Using API key from environment variable")
67
  api_key = env_api_key
68
  # Auto-validate environment API key
69
  if not st.session_state.api_key_validated:
70
  try:
71
  st.session_state.video_processor = VideoProcessor(api_key)
72
  st.session_state.api_key_validated = True
73
- st.success("API key validated successfully")
74
  except Exception as e:
75
- st.error(f"Invalid API key from environment: {str(e)}")
76
  api_key = None
77
  else:
78
- # Direct API key input - users enter their key here
79
  api_key = st.text_input(
80
  "Enter your Gemini API key below:",
81
  type="password",
@@ -84,10 +102,29 @@ def main():
84
  key="api_key_input"
85
  )
86
 
87
- # Show instructions if no API key entered
88
- if not api_key:
89
- st.info("Please enter your Gemini API key above to proceed")
90
- with st.expander("How to obtain your API key"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  st.markdown("""
92
  1. Navigate to [Google AI Studio](https://makersuite.google.com/app/apikey)
93
  2. Sign in with your Google account
@@ -97,126 +134,173 @@ def main():
97
 
98
  **Important:** Keep your API key secure and do not share it publicly.
99
  """)
100
- else:
101
- # Validate the API key when entered
102
- if not st.session_state.api_key_validated or (st.session_state.video_processor is None):
103
- try:
104
- with st.spinner("Validating API key..."):
105
- st.session_state.video_processor = VideoProcessor(api_key)
106
- st.session_state.api_key_validated = True
107
- st.success("API key validated successfully - You can proceed to Step 2")
108
- except Exception as e:
109
- st.error(f"Invalid API key. Please check your key and try again: {str(e)}")
110
- st.session_state.api_key_validated = False
111
- st.session_state.video_processor = None
112
- api_key = None
113
 
114
- # Stop here if no valid API key
115
- if not api_key or not st.session_state.api_key_validated:
116
- st.warning("A valid API key is required to proceed to Steps 2 and 3")
117
- st.stop()
118
 
119
  st.markdown("---")
120
 
121
  # Step 2: Upload Video
122
- st.subheader("Step 2: Video Upload")
123
- uploaded_file = st.file_uploader("Select a video file", type=['mp4', 'mov', 'avi', 'mkv', 'webm'])
 
 
 
 
 
 
 
 
 
124
 
125
  if uploaded_file:
126
  # Validate video file
127
  mime_type = mimetypes.guess_type(uploaded_file.name)[0]
 
 
 
 
128
  if mime_type and mime_type.startswith("video"):
129
- file_size = len(uploaded_file.getvalue()) / (1024**2)
130
 
131
  # Display file info
132
- col1, col2 = st.columns(2)
133
  with col1:
134
- st.info(f"File: {uploaded_file.name}")
135
  with col2:
136
- st.info(f"Size: {file_size:.2f} MB")
 
 
137
 
138
- # Check file size limit (200MB for Gemini)
139
- if file_size > 200:
140
- st.error("File size exceeds limit. Maximum file size is 200MB.")
141
- st.stop()
142
-
143
- # Process new video if different from current
 
144
  if st.session_state.video_name != uploaded_file.name:
 
 
 
 
 
 
 
145
  tmp_path = None
 
 
146
  try:
147
- # Create temporary file
148
- with tempfile.NamedTemporaryFile(delete=False, suffix=Path(uploaded_file.name).suffix) as tmp:
149
- tmp.write(uploaded_file.getvalue())
150
- tmp_path = tmp.name
151
-
152
- # Upload and process with progress indication
153
- with st.spinner("Uploading and processing video..."):
 
 
 
154
  progress_bar = st.progress(0)
155
- progress_bar.progress(25, text="Uploading video...")
156
 
 
 
 
157
  video_file = st.session_state.video_processor.upload_video(tmp_path, uploaded_file.name)
158
- progress_bar.progress(50, text="Processing video...")
159
 
 
 
 
 
 
 
160
  processed_file = st.session_state.video_processor.wait_for_processing(video_file)
161
- progress_bar.progress(100, text="Processing complete")
 
 
 
 
 
 
162
 
163
  # Update session state
164
  st.session_state.video_file = processed_file
165
  st.session_state.video_name = uploaded_file.name
166
  st.session_state.messages = [] # Clear previous conversation
167
 
168
- st.success("Video processed successfully")
169
- time.sleep(1) # Show success message briefly
170
- progress_bar.empty() # Clear progress bar
171
-
172
  except Exception as e:
173
- st.error(f"Error processing video: {str(e)}")
 
 
174
  st.session_state.video_file = None
175
  st.session_state.video_name = None
176
 
177
  finally:
178
  # Clean up temporary file
179
  if tmp_path and os.path.exists(tmp_path):
180
- os.unlink(tmp_path)
 
 
 
 
 
181
 
182
  # Display video player
183
- st.video(uploaded_file.getvalue())
 
184
  else:
185
- st.error("Please upload a valid video file")
186
 
187
  # Control buttons
 
188
  col1, col2, col3 = st.columns(3)
189
  with col1:
190
- if st.button("Reset Chat", disabled=not st.session_state.messages):
191
  st.session_state.messages = []
 
 
192
  st.rerun()
193
 
194
  with col2:
195
- if st.button("Reset Video", disabled=not st.session_state.video_file):
196
  st.session_state.video_file = None
197
  st.session_state.video_name = None
198
  st.session_state.messages = []
 
 
199
  st.rerun()
200
 
201
  with col3:
202
- if st.button("Clear All & Start Over"):
203
  for key in list(st.session_state.keys()):
204
  del st.session_state[key]
 
 
205
  st.rerun()
206
 
207
  st.markdown("---")
208
 
209
  # Step 3: Chat about Video
210
- st.subheader("Step 3: Video Analysis Chat")
211
 
212
  if st.session_state.video_file:
 
 
213
  # Display chat history
214
  for msg in st.session_state.messages:
215
  with st.chat_message(msg["role"]):
216
  st.markdown(msg["content"])
217
 
218
  # Chat input
219
- user_question = st.chat_input("Ask a question about the video...")
 
220
  if user_question:
221
  # Add user message
222
  st.session_state.messages.append({"role": "user", "content": user_question})
@@ -225,20 +309,38 @@ def main():
225
 
226
  # Generate and display assistant response
227
  with st.chat_message("assistant"):
228
- placeholder = st.empty()
229
- with st.spinner("Processing..."):
230
  try:
231
  response = st.session_state.video_processor.chat_with_video(
232
  st.session_state.video_file,
233
  user_question
234
  )
 
 
 
 
235
  except Exception as e:
236
- response = f"Error: {str(e)}"
 
 
237
 
238
- placeholder.markdown(response)
239
  st.session_state.messages.append({"role": "assistant", "content": response})
 
 
 
 
 
 
 
 
 
 
 
240
  else:
241
- st.info("Please upload a video in Step 2 to begin analysis.")
 
 
242
 
243
  if __name__ == "__main__":
244
- main()
 
39
  return f"Error generating response: {str(e)}"
40
 
41
  # Initialize session state properly
42
+ def init_session_state():
43
+ if "messages" not in st.session_state:
44
+ st.session_state.messages = []
45
+ if "video_processor" not in st.session_state:
46
+ st.session_state.video_processor = None
47
+ if "video_file" not in st.session_state:
48
+ st.session_state.video_file = None
49
+ if "video_name" not in st.session_state:
50
+ st.session_state.video_name = None
51
+ if "api_key_validated" not in st.session_state:
52
+ st.session_state.api_key_validated = False
53
+ if "debug_mode" not in st.session_state:
54
+ st.session_state.debug_mode = False
55
 
56
  # Main app function
57
  def main():
58
+ st.set_page_config(page_title="Video Retrieval-Augmented Generation", page_icon="πŸŽ₯", layout="wide")
59
+ st.header("πŸŽ₯ Video Retrieval-Augmented Generation - Gemini 2.0")
60
+
61
+ # Initialize session state
62
+ init_session_state()
63
+
64
+ # Debug mode toggle in sidebar
65
+ with st.sidebar:
66
+ st.session_state.debug_mode = st.checkbox("Debug Mode", value=st.session_state.debug_mode)
67
+ if st.session_state.debug_mode:
68
+ st.write("### Session State:")
69
+ st.write(f"API Key Validated: {st.session_state.api_key_validated}")
70
+ st.write(f"Video File: {'Yes' if st.session_state.video_file else 'No'}")
71
+ st.write(f"Video Name: {st.session_state.video_name}")
72
+ st.write(f"Messages Count: {len(st.session_state.messages)}")
73
+
74
  st.markdown("---")
75
 
76
  # Step 1: API Key input
77
+ st.subheader("πŸ“Œ Step 1: Enter Your API Key")
78
 
79
  # Check for environment variable first
80
  env_api_key = os.environ.get("GOOGLE_API_KEY", "")
81
+ api_key = None
82
 
83
  if env_api_key:
84
+ st.info("βœ… Using API key from environment variable")
85
  api_key = env_api_key
86
  # Auto-validate environment API key
87
  if not st.session_state.api_key_validated:
88
  try:
89
  st.session_state.video_processor = VideoProcessor(api_key)
90
  st.session_state.api_key_validated = True
91
+ st.success("βœ… API key validated successfully")
92
  except Exception as e:
93
+ st.error(f"❌ Invalid API key from environment: {str(e)}")
94
  api_key = None
95
  else:
96
+ # Direct API key input
97
  api_key = st.text_input(
98
  "Enter your Gemini API key below:",
99
  type="password",
 
102
  key="api_key_input"
103
  )
104
 
105
+ if api_key:
106
+ # Add a button to validate the API key
107
+ col1, col2 = st.columns([1, 4])
108
+ with col1:
109
+ validate_button = st.button("Validate Key", type="primary")
110
+
111
+ if validate_button or (api_key and not st.session_state.api_key_validated):
112
+ try:
113
+ with st.spinner("Validating API key..."):
114
+ test_processor = VideoProcessor(api_key)
115
+ st.session_state.video_processor = test_processor
116
+ st.session_state.api_key_validated = True
117
+ st.success("βœ… API key validated successfully!")
118
+ st.balloons()
119
+ time.sleep(1)
120
+ st.rerun()
121
+ except Exception as e:
122
+ st.error(f"❌ Invalid API key: {str(e)}")
123
+ st.session_state.api_key_validated = False
124
+ st.session_state.video_processor = None
125
+ else:
126
+ st.info("ℹ️ Please enter your Gemini API key above to proceed")
127
+ with st.expander("πŸ“– How to obtain your API key"):
128
  st.markdown("""
129
  1. Navigate to [Google AI Studio](https://makersuite.google.com/app/apikey)
130
  2. Sign in with your Google account
 
134
 
135
  **Important:** Keep your API key secure and do not share it publicly.
136
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
+ # Check if we can proceed to next steps
139
+ if not st.session_state.api_key_validated:
140
+ st.warning("⚠️ Please enter a valid API key to proceed to Steps 2 and 3")
141
+ return # Changed from st.stop() to return
142
 
143
  st.markdown("---")
144
 
145
  # Step 2: Upload Video
146
+ st.subheader("πŸ“Ή Step 2: Video Upload")
147
+
148
+ # Show current status
149
+ if st.session_state.video_name:
150
+ st.success(f"βœ… Current video: {st.session_state.video_name}")
151
+
152
+ uploaded_file = st.file_uploader(
153
+ "Select a video file",
154
+ type=['mp4', 'mov', 'avi', 'mkv', 'webm'],
155
+ help="Maximum file size: 200MB"
156
+ )
157
 
158
  if uploaded_file:
159
  # Validate video file
160
  mime_type = mimetypes.guess_type(uploaded_file.name)[0]
161
+
162
+ if st.session_state.debug_mode:
163
+ st.info(f"Debug: MIME type detected: {mime_type}")
164
+
165
  if mime_type and mime_type.startswith("video"):
166
+ file_size_mb = len(uploaded_file.getvalue()) / (1024**2)
167
 
168
  # Display file info
169
+ col1, col2, col3 = st.columns(3)
170
  with col1:
171
+ st.metric("File", uploaded_file.name)
172
  with col2:
173
+ st.metric("Size", f"{file_size_mb:.2f} MB")
174
+ with col3:
175
+ st.metric("Type", mime_type.split('/')[-1].upper())
176
 
177
+ # Check file size limit
178
+ if file_size_mb > 200:
179
+ st.error("❌ File size exceeds 200MB limit")
180
+ return
181
+
182
+ # Process button
183
+ process_video = False
184
  if st.session_state.video_name != uploaded_file.name:
185
+ if st.button("πŸš€ Process Video", type="primary", use_container_width=True):
186
+ process_video = True
187
+ else:
188
+ st.info("ℹ️ This video has already been processed")
189
+
190
+ # Process new video
191
+ if process_video:
192
  tmp_path = None
193
+ progress_container = st.container()
194
+
195
  try:
196
+ with progress_container:
197
+ # Create temporary file
198
+ with tempfile.NamedTemporaryFile(delete=False, suffix=Path(uploaded_file.name).suffix) as tmp:
199
+ tmp.write(uploaded_file.getvalue())
200
+ tmp_path = tmp.name
201
+
202
+ if st.session_state.debug_mode:
203
+ st.info(f"Debug: Temp file created at {tmp_path}")
204
+
205
+ # Upload and process with detailed progress
206
  progress_bar = st.progress(0)
207
+ status_text = st.empty()
208
 
209
+ # Step 1: Upload
210
+ status_text.text("πŸ“€ Uploading video to Gemini...")
211
+ progress_bar.progress(25)
212
  video_file = st.session_state.video_processor.upload_video(tmp_path, uploaded_file.name)
 
213
 
214
+ if st.session_state.debug_mode:
215
+ st.info(f"Debug: Video uploaded, state: {video_file.state.name}")
216
+
217
+ # Step 2: Process
218
+ status_text.text("⏳ Processing video (this may take a minute)...")
219
+ progress_bar.progress(50)
220
  processed_file = st.session_state.video_processor.wait_for_processing(video_file)
221
+
222
+ if st.session_state.debug_mode:
223
+ st.info(f"Debug: Video processed, final state: {processed_file.state.name}")
224
+
225
+ # Step 3: Complete
226
+ progress_bar.progress(100)
227
+ status_text.text("βœ… Video ready for analysis!")
228
 
229
  # Update session state
230
  st.session_state.video_file = processed_file
231
  st.session_state.video_name = uploaded_file.name
232
  st.session_state.messages = [] # Clear previous conversation
233
 
234
+ st.success("πŸŽ‰ Video processed successfully! You can now ask questions below.")
235
+ time.sleep(2)
236
+ st.rerun() # Refresh to show chat interface
237
+
238
  except Exception as e:
239
+ st.error(f"❌ Error processing video: {str(e)}")
240
+ if st.session_state.debug_mode:
241
+ st.exception(e)
242
  st.session_state.video_file = None
243
  st.session_state.video_name = None
244
 
245
  finally:
246
  # Clean up temporary file
247
  if tmp_path and os.path.exists(tmp_path):
248
+ try:
249
+ os.unlink(tmp_path)
250
+ if st.session_state.debug_mode:
251
+ st.info("Debug: Temp file cleaned up")
252
+ except:
253
+ pass
254
 
255
  # Display video player
256
+ if uploaded_file:
257
+ st.video(uploaded_file.getvalue())
258
  else:
259
+ st.error("❌ Please upload a valid video file")
260
 
261
  # Control buttons
262
+ st.markdown("---")
263
  col1, col2, col3 = st.columns(3)
264
  with col1:
265
+ if st.button("πŸ”„ Reset Chat", disabled=not st.session_state.messages, use_container_width=True):
266
  st.session_state.messages = []
267
+ st.success("Chat history cleared!")
268
+ time.sleep(1)
269
  st.rerun()
270
 
271
  with col2:
272
+ if st.button("πŸ“Ή Reset Video", disabled=not st.session_state.video_file, use_container_width=True):
273
  st.session_state.video_file = None
274
  st.session_state.video_name = None
275
  st.session_state.messages = []
276
+ st.success("Video reset!")
277
+ time.sleep(1)
278
  st.rerun()
279
 
280
  with col3:
281
+ if st.button("πŸ—‘οΈ Clear All", type="secondary", use_container_width=True):
282
  for key in list(st.session_state.keys()):
283
  del st.session_state[key]
284
+ st.success("All data cleared!")
285
+ time.sleep(1)
286
  st.rerun()
287
 
288
  st.markdown("---")
289
 
290
  # Step 3: Chat about Video
291
+ st.subheader("πŸ’¬ Step 3: Video Analysis Chat")
292
 
293
  if st.session_state.video_file:
294
+ st.success(f"βœ… Ready to analyze: {st.session_state.video_name}")
295
+
296
  # Display chat history
297
  for msg in st.session_state.messages:
298
  with st.chat_message(msg["role"]):
299
  st.markdown(msg["content"])
300
 
301
  # Chat input
302
+ user_question = st.chat_input("Ask a question about the video...", key="chat_input")
303
+
304
  if user_question:
305
  # Add user message
306
  st.session_state.messages.append({"role": "user", "content": user_question})
 
309
 
310
  # Generate and display assistant response
311
  with st.chat_message("assistant"):
312
+ with st.spinner("πŸ€” Analyzing video..."):
 
313
  try:
314
  response = st.session_state.video_processor.chat_with_video(
315
  st.session_state.video_file,
316
  user_question
317
  )
318
+
319
+ if st.session_state.debug_mode:
320
+ st.info(f"Debug: Response length: {len(response)} characters")
321
+
322
  except Exception as e:
323
+ response = f"❌ Error: {str(e)}"
324
+ if st.session_state.debug_mode:
325
+ st.exception(e)
326
 
327
+ st.markdown(response)
328
  st.session_state.messages.append({"role": "assistant", "content": response})
329
+
330
+ # Sample questions
331
+ with st.expander("πŸ’‘ Sample Questions"):
332
+ st.markdown("""
333
+ - What is happening in this video?
334
+ - Can you describe the main events?
335
+ - What objects or people can you see?
336
+ - What is the mood or atmosphere?
337
+ - Can you provide a summary of the video?
338
+ - What are the key moments in the video?
339
+ """)
340
  else:
341
+ st.info("πŸ“€ Please upload and process a video in Step 2 to begin analysis.")
342
+ if st.session_state.debug_mode:
343
+ st.warning("Debug: No video file in session state")
344
 
345
  if __name__ == "__main__":
346
+ main()