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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -219
app.py CHANGED
@@ -6,6 +6,13 @@ import time
6
  import mimetypes
7
  from pathlib import Path
8
 
 
 
 
 
 
 
 
9
  # VideoProcessor class
10
  class VideoProcessor:
11
  def __init__(self, api_key):
@@ -39,268 +46,123 @@ class VideoProcessor:
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",
100
- placeholder="AIzaSy...",
101
- help="Get your API key from https://makersuite.google.com/app/apikey",
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
131
- 3. Click on "Get API key" or "Create API key"
132
- 4. Copy the generated API key
133
- 5. Paste it in the field above
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,38 +171,20 @@ def main():
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()
 
6
  import mimetypes
7
  from pathlib import Path
8
 
9
+ # --- Get API key from environment variable or user input ---
10
+ def get_api_key():
11
+ GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY", "")
12
+ if not GOOGLE_API_KEY:
13
+ GOOGLE_API_KEY = st.text_input("Enter your Gemini API key", type="password")
14
+ return GOOGLE_API_KEY or "AIzaSyA8TTu9s6fJDG9RlMwOyHFxg270xLgpiyE" # Warning: Hardcoded key
15
+
16
  # VideoProcessor class
17
  class VideoProcessor:
18
  def __init__(self, api_key):
 
46
  return f"Error generating response: {str(e)}"
47
 
48
  # Initialize session state properly
49
+ if "messages" not in st.session_state:
50
+ st.session_state.messages = []
51
+ if "video_processor" not in st.session_state:
52
+ st.session_state.video_processor = None
53
+ if "video_file" not in st.session_state:
54
+ st.session_state.video_file = None
55
+ if "video_name" not in st.session_state:
56
+ st.session_state.video_name = None
 
 
 
 
 
57
 
58
  # Main app function
59
  def main():
60
+ st.set_page_config(page_title="Video Retrieval-Augmented Generation", page_icon="🎬", layout="wide")
61
+ st.header("🎬 Video Retrieval-Augmented Generation - Gemini 2.0")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  st.markdown("---")
63
 
64
  # Step 1: API Key input
65
+ #st.subheader("Step 1: Enter your Gemini API key")
66
+ api_key = get_api_key()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
+ if not api_key:
69
+ st.error("Please enter your API key to proceed.")
70
+ st.stop()
 
 
 
71
 
72
  # Step 2: Upload Video
73
+ st.subheader("Step 2: Upload your video file")
74
+ uploaded_file = st.file_uploader("Upload a video", type=['mp4', 'mov', 'avi', 'mkv', 'webm'])
 
 
 
 
 
 
 
 
 
75
 
76
  if uploaded_file:
77
  # Validate video file
78
  mime_type = mimetypes.guess_type(uploaded_file.name)[0]
 
 
 
 
79
  if mime_type and mime_type.startswith("video"):
80
+ file_size = len(uploaded_file.getvalue()) / (1024**2)
81
 
82
  # Display file info
83
+ col1, col2 = st.columns(2)
84
  with col1:
85
+ st.info(f"πŸ“ File: {uploaded_file.name}")
86
  with col2:
87
+ st.info(f"πŸ’Ύ Size: {file_size:.2f} MB")
 
 
88
 
89
+ # Check file size limit (200MB for Gemini)
90
+ if file_size > 200:
91
+ st.error("❌ File too large! Maximum size is 200MB")
92
+ st.stop()
 
 
 
 
 
 
 
 
93
 
94
+ # Process new video if different from current
95
+ if st.session_state.video_name != uploaded_file.name:
96
  tmp_path = None
 
 
97
  try:
98
+ # Initialize processor if needed
99
+ if not st.session_state.video_processor:
100
+ st.session_state.video_processor = VideoProcessor(api_key)
101
+
102
+ # Create temporary file
103
+ with tempfile.NamedTemporaryFile(delete=False, suffix=Path(uploaded_file.name).suffix) as tmp:
104
+ tmp.write(uploaded_file.getvalue())
105
+ tmp_path = tmp.name
106
+
107
+ # Upload and process with progress indication
108
+ with st.spinner("πŸ“€ Uploading and processing video..."):
109
  progress_bar = st.progress(0)
110
+ progress_bar.progress(25, text="Uploading video...")
111
 
 
 
 
112
  video_file = st.session_state.video_processor.upload_video(tmp_path, uploaded_file.name)
113
+ progress_bar.progress(50, text="Processing video...")
114
 
 
 
 
 
 
 
115
  processed_file = st.session_state.video_processor.wait_for_processing(video_file)
116
+ progress_bar.progress(100, text="Complete!")
 
 
 
 
 
 
117
 
118
  # Update session state
119
  st.session_state.video_file = processed_file
120
  st.session_state.video_name = uploaded_file.name
121
  st.session_state.messages = [] # Clear previous conversation
122
 
123
+ st.success("βœ… Video processed successfully!")
124
+ time.sleep(1) # Show success message briefly
125
+ progress_bar.empty() # Clear progress bar
126
+
127
  except Exception as e:
128
  st.error(f"❌ Error processing video: {str(e)}")
 
 
129
  st.session_state.video_file = None
130
  st.session_state.video_name = None
131
 
132
  finally:
133
  # Clean up temporary file
134
  if tmp_path and os.path.exists(tmp_path):
135
+ os.unlink(tmp_path)
 
 
 
 
 
136
 
137
  # Display video player
138
+ st.video(uploaded_file.getvalue())
 
139
  else:
140
  st.error("❌ Please upload a valid video file")
141
 
142
  # Control buttons
143
+ col1, col2 = st.columns(2)
 
144
  with col1:
145
+ if st.button("πŸ”„ Reset Chat", disabled=not st.session_state.messages):
146
  st.session_state.messages = []
 
 
147
  st.rerun()
148
 
149
  with col2:
150
+ if st.button("πŸ—‘οΈ Reset All", disabled=not st.session_state.video_file):
 
 
 
 
 
 
 
 
 
151
  for key in list(st.session_state.keys()):
152
  del st.session_state[key]
 
 
153
  st.rerun()
154
 
 
 
155
  # Step 3: Chat about Video
156
+ st.subheader("Step 3: Chat with your video")
157
 
158
  if st.session_state.video_file:
 
 
159
  # Display chat history
160
  for msg in st.session_state.messages:
161
  with st.chat_message(msg["role"]):
162
  st.markdown(msg["content"])
163
 
164
  # Chat input
165
+ user_question = st.chat_input("Ask a question about the video...")
 
166
  if user_question:
167
  # Add user message
168
  st.session_state.messages.append({"role": "user", "content": user_question})
 
171
 
172
  # Generate and display assistant response
173
  with st.chat_message("assistant"):
174
+ placeholder = st.empty()
175
+ with st.spinner("πŸ€” Thinking..."):
176
  try:
177
  response = st.session_state.video_processor.chat_with_video(
178
  st.session_state.video_file,
179
  user_question
180
  )
 
 
 
 
181
  except Exception as e:
182
  response = f"❌ Error: {str(e)}"
 
 
183
 
184
+ placeholder.markdown(response)
185
  st.session_state.messages.append({"role": "assistant", "content": response})
 
 
 
 
 
 
 
 
 
 
 
186
  else:
187
+ st.info("πŸ“Ή Please upload a video in Step 2 to start chatting.")
 
 
188
 
189
  if __name__ == "__main__":
190
  main()