Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import google.generativeai as genai | |
| import os | |
| import tempfile | |
| import time | |
| # Configure page | |
| st.set_page_config( | |
| page_title="Video AI Analysis", | |
| page_icon="π₯", | |
| layout="wide" | |
| ) | |
| # Initialize session state | |
| if 'show_recorder' not in st.session_state: | |
| st.session_state.show_recorder = False | |
| # Title | |
| st.title("π₯ Video Recording & AI Analysis") | |
| st.markdown("Upload or record a video to get instant AI-powered insights") | |
| st.divider() | |
| # Get API key | |
| def get_api_key(): | |
| # Try environment variable first (for Hugging Face Spaces) | |
| api_key = os.environ.get("GOOGLE_API_KEY", "") | |
| # If not found, allow manual input | |
| if not api_key: | |
| api_key = st.sidebar.text_input( | |
| "Enter Gemini API key:", | |
| type="password", | |
| help="Set this in HF Spaces secrets for production" | |
| ) | |
| return api_key | |
| # Initialize Gemini | |
| def init_gemini(api_key): | |
| if api_key: | |
| genai.configure(api_key=api_key) | |
| return genai.GenerativeModel("gemini-2.0-flash-exp") | |
| return None | |
| # Process video | |
| def process_video(model, video_bytes, filename): | |
| # Save to temp file | |
| with tempfile.NamedTemporaryFile(delete=False, suffix='.mp4') as tmp: | |
| tmp.write(video_bytes) | |
| tmp_path = tmp.name | |
| try: | |
| # Upload to Gemini | |
| with st.spinner("π€ Uploading video..."): | |
| video_file = genai.upload_file(path=tmp_path, display_name=filename) | |
| # Wait for processing | |
| with st.spinner("β³ Processing... (30-60 seconds)"): | |
| attempts = 0 | |
| while video_file.state.name == "PROCESSING" and attempts < 30: | |
| time.sleep(2) | |
| video_file = genai.get_file(video_file.name) | |
| attempts += 1 | |
| if video_file.state.name == "FAILED": | |
| raise Exception("Video processing failed") | |
| elif video_file.state.name == "PROCESSING": | |
| raise Exception("Processing timeout - try a shorter video") | |
| # Generate summary | |
| with st.spinner("π€ Generating AI summary..."): | |
| prompt = """Analyze this video and provide a summary including: | |
| 1. Main content and activities | |
| 2. Key moments or information | |
| 3. Visual elements (people, objects, scenes) | |
| 4. Audio/speech content if present | |
| 5. Overall purpose or message | |
| Format as a clear, structured summary.""" | |
| response = model.generate_content([video_file, prompt]) | |
| return response.text | |
| finally: | |
| # Clean up | |
| if os.path.exists(tmp_path): | |
| os.unlink(tmp_path) | |
| # Sidebar | |
| with st.sidebar: | |
| st.markdown("### π Configuration") | |
| api_key = get_api_key() | |
| if api_key: | |
| st.success("β API Key set") | |
| else: | |
| st.warning("β οΈ API Key required") | |
| st.divider() | |
| st.markdown("### π Instructions") | |
| st.markdown(""" | |
| 1. Set API key (HF secrets) | |
| 2. Upload/record video | |
| 3. Click Analyze | |
| 4. View summary | |
| """) | |
| st.divider() | |
| st.markdown("### π Links") | |
| st.markdown("[Get API Key](https://makersuite.google.com/app/apikey)") | |
| st.markdown("[Documentation](https://ai.google.dev)") | |
| if st.button("π Reset"): | |
| st.cache_data.clear() | |
| st.cache_resource.clear() | |
| st.rerun() | |
| # Main content | |
| if not api_key: | |
| st.error("Please enter your Gemini API key in the sidebar") | |
| st.info(""" | |
| **For Hugging Face Spaces:** | |
| 1. Go to Settings β Repository secrets | |
| 2. Add 'GOOGLE_API_KEY' secret | |
| 3. Paste your Gemini API key | |
| """) | |
| else: | |
| # Initialize model | |
| model = init_gemini(api_key) | |
| if model: | |
| # Create tabs | |
| tab1, tab2 = st.tabs(["π€ Upload Video", "πΉ Record Video"]) | |
| with tab1: | |
| uploaded = st.file_uploader( | |
| "Choose video file (max 50MB recommended)", | |
| type=['mp4', 'mov', 'avi', 'webm'] | |
| ) | |
| if uploaded: | |
| st.video(uploaded) | |
| if st.button("π Analyze Upload", type="primary", key="analyze_upload"): | |
| try: | |
| video_bytes = uploaded.getvalue() | |
| summary = process_video(model, video_bytes, uploaded.name) | |
| st.success("β Analysis complete!") | |
| st.divider() | |
| st.subheader("π Video Summary") | |
| st.write(summary) | |
| # Download button | |
| st.download_button( | |
| "π₯ Download Summary", | |
| summary, | |
| "video_summary.txt", | |
| "text/plain" | |
| ) | |
| except Exception as e: | |
| st.error(f"Error: {str(e)}") | |
| with tab2: | |
| st.info("π± Works best on mobile devices") | |
| recorded = st.camera_input("Click to record") | |
| if recorded: | |
| st.video(recorded) | |
| if st.button("π Analyze Recording", type="primary", key="analyze_record"): | |
| try: | |
| recorded.seek(0) | |
| video_bytes = recorded.read() | |
| summary = process_video(model, video_bytes, "recording.mp4") | |
| st.success("β Analysis complete!") | |
| st.divider() | |
| st.subheader("π Video Summary") | |
| st.write(summary) | |
| # Download button | |
| st.download_button( | |
| "π₯ Download Summary", | |
| summary, | |
| "recording_summary.txt", | |
| "text/plain" | |
| ) | |
| except Exception as e: | |
| st.error(f"Error: {str(e)}") | |
| else: | |
| st.error("Failed to initialize Gemini model") | |
| # Footer | |
| st.divider() | |
| st.caption("Powered by Google Gemini 2.0 | Built with Streamlit") |