Naveen-2007 commited on
Commit
231cfe3
ยท
1 Parent(s): 34a913a

Redesign Video Brain: Step 1=Enter URL, Step 2=Auto-analyze, Step 3=Ask follow-up questions

Browse files
Files changed (1) hide show
  1. streamlit_app.py +228 -128
streamlit_app.py CHANGED
@@ -32,6 +32,10 @@ if "youtube_url" not in st.session_state:
32
  st.session_state.youtube_url = ""
33
  if "video_loaded" not in st.session_state:
34
  st.session_state.video_loaded = False
 
 
 
 
35
  if "product_ideas" not in st.session_state:
36
  st.session_state.product_ideas = []
37
 
@@ -594,59 +598,84 @@ else:
594
 
595
 
596
  # =====================================
597
- # UNIFIED SEARCH BOX (All elements inside)
598
  # =====================================
599
- st.markdown('<div class="search-wrapper">', unsafe_allow_html=True)
600
-
601
- # Use a form so Enter key submits
602
- with st.form(key="search_form", clear_on_submit=False):
603
- col1, col2, col3, col4 = st.columns([2, 8, 1, 1])
604
-
605
- with col1:
606
- # Mode selector dropdown
607
- mode_list = list(MODES.keys())
608
- current_idx = mode_list.index(st.session_state.mode)
609
- selected = st.selectbox(
610
- "mode",
611
- mode_list,
612
- index=current_idx,
613
- format_func=lambda x: f"{MODES[x]['icon']} {x}",
614
- label_visibility="collapsed",
615
- key="mode_select"
616
- )
617
-
618
- with col2:
619
- # Search input - Enter key will submit the form
620
- query = st.text_input(
621
- "search",
622
- placeholder="Ask anything... (Press Enter to search)",
623
- label_visibility="collapsed",
624
- key="query_input"
625
- )
626
-
627
- with col3:
628
- # Placeholder for alignment
629
- st.write("")
630
-
631
- with col4:
632
- # Submit button
633
- submit = st.form_submit_button("โ†’", help="Search")
634
 
635
- # Handle mode change outside form
636
- if selected != st.session_state.mode:
637
- st.session_state.mode = selected
638
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
639
 
640
- # File upload button (outside form)
641
- col_attach, col_spacer_attach = st.columns([1, 11])
642
- with col_attach:
643
- if st.button("๐Ÿ“Ž Attach files", key="attach_btn"):
644
- st.session_state.show_upload = not st.session_state.show_upload
645
 
646
- st.markdown('</div>', unsafe_allow_html=True)
 
647
 
648
- # Mode description
649
- st.markdown(f'<div class="mode-desc">{MODES[st.session_state.mode]["icon"]} {st.session_state.mode}: {MODES[st.session_state.mode]["desc"]}</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
650
 
651
  # =====================================
652
  # SPECIAL UI FOR PRODUCT MVP MODE
@@ -666,61 +695,165 @@ if st.session_state.mode == "Product MVP" and not st.session_state.current_resul
666
  # =====================================
667
  # SPECIAL UI FOR VIDEO BRAIN MODE
668
  # =====================================
669
- if "video_transcript" not in st.session_state:
670
- st.session_state.video_transcript = ""
671
-
672
- if st.session_state.mode == "Video Brain" and not st.session_state.current_result:
673
  st.markdown("""
674
  <div style="text-align: center; padding: 20px; margin: 20px auto; max-width: 700px;
675
  background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%);
676
  border-radius: 16px; color: white;">
677
  <h3 style="margin: 0; font-size: 24px;">๐ŸŽฅ Video Brain โ€“ Understand Any YouTube Video</h3>
678
- <p style="margin: 10px 0 0; opacity: 0.9;">๐Ÿ“‹ Paste the video transcript for accurate analysis</p>
679
  </div>
680
  """, unsafe_allow_html=True)
681
 
682
- st.markdown("""
683
- **How to use Video Brain:**
684
- 1. Open your YouTube video
685
- 2. Click **โ‹ฎ** (three dots) โ†’ **Show transcript**
686
- 3. Copy the transcript text and paste below
687
- 4. Ask questions about the video!
688
- """)
689
-
690
- # YouTube URL input (optional, for reference)
691
- youtube_url = st.text_input(
692
- "YouTube URL (optional)",
693
- value=st.session_state.youtube_url,
694
- placeholder="Paste YouTube URL here for reference",
695
- key="youtube_url_input"
696
- )
697
-
698
- if youtube_url and ("youtube.com" in youtube_url or "youtu.be" in youtube_url):
699
- if youtube_url != st.session_state.youtube_url:
700
- st.session_state.youtube_url = youtube_url
701
- st.session_state.video_loaded = True
702
-
703
- # TRANSCRIPT INPUT - Main feature
704
- st.markdown("### ๐Ÿ“‹ Paste Video Transcript")
705
- transcript_input = st.text_area(
706
- "Video Transcript",
707
- value=st.session_state.video_transcript,
708
- placeholder="Paste the YouTube transcript here...\n\nTo get it: Open YouTube video โ†’ Click โ‹ฎ โ†’ Show transcript โ†’ Select All โ†’ Copy",
709
- height=200,
710
- key="transcript_input"
711
- )
712
-
713
- if transcript_input and transcript_input != st.session_state.video_transcript:
714
- st.session_state.video_transcript = transcript_input
715
- st.session_state.video_loaded = True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716
 
717
- if st.session_state.video_transcript:
718
- word_count = len(st.session_state.video_transcript.split())
719
- st.success(f"โœ… Transcript loaded! ({word_count} words) - Now ask questions below.")
720
- elif st.session_state.video_loaded and st.session_state.youtube_url:
721
- st.info("๐Ÿ’ก For best results, also paste the transcript above")
722
  else:
723
- st.info("๐Ÿ‘† Paste the video transcript above to get started")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
 
725
  # Show file uploader when icon is clicked
726
  if st.session_state.show_upload:
@@ -747,45 +880,12 @@ if st.session_state.uploaded_files:
747
 
748
 
749
  # =====================================
750
- # HANDLE SEARCH
751
  # =====================================
752
- if submit and query.strip():
753
  extra_data = None
754
  actual_query = query.strip()
755
 
756
- # For Video Brain mode, include the YouTube URL and transcript
757
- if st.session_state.mode == "Video Brain":
758
- # Check if query itself contains a YouTube URL
759
- query_text = query.strip()
760
- url_in_query = None
761
- for word in query_text.split():
762
- if "youtube.com" in word or "youtu.be" in word:
763
- url_in_query = word
764
- break
765
-
766
- if url_in_query:
767
- # User pasted URL directly in the query
768
- st.session_state.youtube_url = url_in_query
769
- st.session_state.video_loaded = True
770
- extra_data = {"youtube_url": url_in_query}
771
- # If query is JUST the URL, ask a default question
772
- if query_text == url_in_query:
773
- actual_query = "Summarize this video and give me the key takeaways"
774
- elif st.session_state.video_loaded and st.session_state.youtube_url:
775
- extra_data = {"youtube_url": st.session_state.youtube_url}
776
- elif st.session_state.get("video_transcript"):
777
- # User has transcript but no URL - still allow it
778
- extra_data = {"youtube_url": "user_provided_transcript"}
779
- else:
780
- st.warning("โš ๏ธ Please paste a YouTube URL or transcript above!")
781
- st.stop()
782
-
783
- # Include pasted transcript if available
784
- if st.session_state.get("video_transcript"):
785
- if extra_data is None:
786
- extra_data = {}
787
- extra_data["transcript"] = st.session_state.video_transcript
788
-
789
  # For Product MVP mode, save to ideas history
790
  if st.session_state.mode == "Product MVP":
791
  st.session_state.product_ideas.append({
 
32
  st.session_state.youtube_url = ""
33
  if "video_loaded" not in st.session_state:
34
  st.session_state.video_loaded = False
35
+ if "video_summary" not in st.session_state:
36
+ st.session_state.video_summary = None # Stores the initial video analysis
37
+ if "video_transcript" not in st.session_state:
38
+ st.session_state.video_transcript = ""
39
  if "product_ideas" not in st.session_state:
40
  st.session_state.product_ideas = []
41
 
 
598
 
599
 
600
  # =====================================
601
+ # UNIFIED SEARCH BOX (Hide for Video Brain - it has dedicated UI)
602
  # =====================================
603
+ if st.session_state.mode != "Video Brain":
604
+ st.markdown('<div class="search-wrapper">', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
 
606
+ # Use a form so Enter key submits
607
+ with st.form(key="search_form", clear_on_submit=False):
608
+ col1, col2, col3, col4 = st.columns([2, 8, 1, 1])
609
+
610
+ with col1:
611
+ # Mode selector dropdown
612
+ mode_list = list(MODES.keys())
613
+ current_idx = mode_list.index(st.session_state.mode)
614
+ selected = st.selectbox(
615
+ "mode",
616
+ mode_list,
617
+ index=current_idx,
618
+ format_func=lambda x: f"{MODES[x]['icon']} {x}",
619
+ label_visibility="collapsed",
620
+ key="mode_select"
621
+ )
622
+
623
+ with col2:
624
+ # Search input - Enter key will submit the form
625
+ query = st.text_input(
626
+ "search",
627
+ placeholder="Ask anything... (Press Enter to search)",
628
+ label_visibility="collapsed",
629
+ key="query_input"
630
+ )
631
+
632
+ with col3:
633
+ # Placeholder for alignment
634
+ st.write("")
635
+
636
+ with col4:
637
+ # Submit button
638
+ submit = st.form_submit_button("โ†’", help="Search")
639
+
640
+ # Handle mode change outside form
641
+ if selected != st.session_state.mode:
642
+ st.session_state.mode = selected
643
+ st.rerun()
644
+
645
+ # File upload button (outside form)
646
+ col_attach, col_spacer_attach = st.columns([1, 11])
647
+ with col_attach:
648
+ if st.button("๐Ÿ“Ž Attach files", key="attach_btn"):
649
+ st.session_state.show_upload = not st.session_state.show_upload
650
 
651
+ st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
652
 
653
+ # Mode description
654
+ st.markdown(f'<div class="mode-desc">{MODES[st.session_state.mode]["icon"]} {st.session_state.mode}: {MODES[st.session_state.mode]["desc"]}</div>', unsafe_allow_html=True)
655
 
656
+ else:
657
+ # Video Brain mode - just show mode selector
658
+ mode_list = list(MODES.keys())
659
+ current_idx = mode_list.index(st.session_state.mode)
660
+ selected = st.selectbox(
661
+ "Switch Mode",
662
+ mode_list,
663
+ index=current_idx,
664
+ format_func=lambda x: f"{MODES[x]['icon']} {x}",
665
+ key="mode_select_video"
666
+ )
667
+ if selected != st.session_state.mode:
668
+ st.session_state.mode = selected
669
+ # Reset video state when switching away
670
+ st.session_state.video_summary = None
671
+ st.session_state.video_loaded = False
672
+ st.session_state.youtube_url = ""
673
+ st.session_state.video_transcript = ""
674
+ st.rerun()
675
+
676
+ # Initialize these for Video Brain mode
677
+ query = ""
678
+ submit = False
679
 
680
  # =====================================
681
  # SPECIAL UI FOR PRODUCT MVP MODE
 
695
  # =====================================
696
  # SPECIAL UI FOR VIDEO BRAIN MODE
697
  # =====================================
698
+ if st.session_state.mode == "Video Brain":
699
+ # Header
 
 
700
  st.markdown("""
701
  <div style="text-align: center; padding: 20px; margin: 20px auto; max-width: 700px;
702
  background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%);
703
  border-radius: 16px; color: white;">
704
  <h3 style="margin: 0; font-size: 24px;">๐ŸŽฅ Video Brain โ€“ Understand Any YouTube Video</h3>
705
+ <p style="margin: 10px 0 0; opacity: 0.9;">Enter a YouTube URL to analyze the video</p>
706
  </div>
707
  """, unsafe_allow_html=True)
708
 
709
+ # STEP 1: If no video loaded yet, show URL input
710
+ if not st.session_state.video_summary:
711
+ st.markdown("### Step 1: Enter YouTube URL")
712
+
713
+ video_url_col, load_btn_col = st.columns([4, 1])
714
+ with video_url_col:
715
+ youtube_url_input = st.text_input(
716
+ "YouTube URL",
717
+ value=st.session_state.youtube_url,
718
+ placeholder="https://www.youtube.com/watch?v=...",
719
+ key="video_url_input",
720
+ label_visibility="collapsed"
721
+ )
722
+
723
+ with load_btn_col:
724
+ load_video = st.button("๐ŸŽฌ Load", key="load_video_btn", use_container_width=True)
725
+
726
+ # Also allow transcript paste as alternative
727
+ with st.expander("๐Ÿ“‹ Or paste transcript manually (if URL doesn't work)"):
728
+ transcript_input = st.text_area(
729
+ "Paste transcript here",
730
+ value=st.session_state.video_transcript,
731
+ placeholder="Open YouTube โ†’ Click โ‹ฎ โ†’ Show transcript โ†’ Copy all text",
732
+ height=150,
733
+ key="transcript_paste_input"
734
+ )
735
+ if transcript_input != st.session_state.video_transcript:
736
+ st.session_state.video_transcript = transcript_input
737
+
738
+ # Handle Load button click
739
+ if load_video and youtube_url_input:
740
+ if "youtube.com" in youtube_url_input or "youtu.be" in youtube_url_input:
741
+ st.session_state.youtube_url = youtube_url_input
742
+
743
+ # Call API to analyze video
744
+ with st.spinner("๐Ÿ”„ Analyzing video... This may take a moment..."):
745
+ payload = {
746
+ "message": "Summarize this video completely. Give me: 1) What the video is about, 2) Key points and takeaways, 3) Important details mentioned, 4) Main conclusions",
747
+ "workspace_id": WORKSPACE,
748
+ "mode": "video_brain",
749
+ "youtube_url": youtube_url_input,
750
+ "transcript": st.session_state.video_transcript
751
+ }
752
+ try:
753
+ response = requests.post(f"{API_URL}/api/video_brain", json=payload, timeout=180)
754
+ if response.ok:
755
+ result = response.json()
756
+ st.session_state.video_summary = result
757
+ st.session_state.video_loaded = True
758
+ st.rerun()
759
+ else:
760
+ st.error(f"Error loading video: {response.text}")
761
+ except Exception as e:
762
+ st.error(f"Error: {str(e)}")
763
+ else:
764
+ st.warning("โš ๏ธ Please enter a valid YouTube URL")
765
+
766
+ # Also handle Enter key in URL input
767
+ if youtube_url_input and youtube_url_input != st.session_state.youtube_url:
768
+ if "youtube.com" in youtube_url_input or "youtu.be" in youtube_url_input:
769
+ st.session_state.youtube_url = youtube_url_input
770
 
771
+ # STEP 2: Video is loaded - show summary and question input
 
 
 
 
772
  else:
773
+ # Show video info
774
+ st.markdown(f"**๐Ÿ“บ Loaded Video:** `{st.session_state.youtube_url}`")
775
+
776
+ # Button to load different video
777
+ if st.button("๐Ÿ”„ Load Different Video", key="reset_video"):
778
+ st.session_state.video_summary = None
779
+ st.session_state.video_loaded = False
780
+ st.session_state.youtube_url = ""
781
+ st.session_state.video_transcript = ""
782
+ st.session_state.current_result = None
783
+ st.rerun()
784
+
785
+ st.markdown("---")
786
+
787
+ # Show the video summary
788
+ st.markdown("### ๐Ÿ“ Video Summary")
789
+ summary_data = st.session_state.video_summary
790
+ st.markdown(summary_data.get("answer", "No summary available"))
791
+
792
+ # Show sources if available
793
+ if summary_data.get("sources"):
794
+ with st.expander("๐Ÿ“š Sources"):
795
+ for src in summary_data["sources"]:
796
+ st.markdown(f"- [{src.get('title', 'Source')}]({src.get('url', '#')})")
797
+
798
+ st.markdown("---")
799
+
800
+ # STEP 3: Ask follow-up questions
801
+ st.markdown("### ๐Ÿ’ฌ Ask Questions About This Video")
802
+
803
+ followup_question = st.text_input(
804
+ "Your question",
805
+ placeholder="Ask anything about the video...",
806
+ key="video_followup_input",
807
+ label_visibility="collapsed"
808
+ )
809
+
810
+ ask_btn = st.button("๐Ÿ” Ask", key="ask_followup_btn")
811
+
812
+ # Quick question buttons
813
+ st.markdown("**Quick questions:**")
814
+ quick_q_cols = st.columns(3)
815
+ quick_questions = [
816
+ "What are the main points?",
817
+ "Explain in simple terms",
818
+ "What should I remember?"
819
+ ]
820
+
821
+ selected_quick_q = None
822
+ for i, qq in enumerate(quick_questions):
823
+ with quick_q_cols[i]:
824
+ if st.button(qq, key=f"quick_q_{i}"):
825
+ selected_quick_q = qq
826
+
827
+ # Handle question submission
828
+ question_to_ask = followup_question if ask_btn and followup_question else selected_quick_q
829
+
830
+ if question_to_ask:
831
+ with st.spinner("๐Ÿค” Thinking..."):
832
+ payload = {
833
+ "message": question_to_ask,
834
+ "workspace_id": WORKSPACE,
835
+ "mode": "video_brain",
836
+ "youtube_url": st.session_state.youtube_url,
837
+ "transcript": st.session_state.video_transcript
838
+ }
839
+ try:
840
+ response = requests.post(f"{API_URL}/api/video_brain", json=payload, timeout=180)
841
+ if response.ok:
842
+ result = response.json()
843
+ st.session_state.current_result = {
844
+ "query": question_to_ask,
845
+ "mode": "Video Brain",
846
+ "data": result
847
+ }
848
+ st.rerun()
849
+ except Exception as e:
850
+ st.error(f"Error: {str(e)}")
851
+
852
+ # Show previous Q&A if exists
853
+ if st.session_state.current_result and st.session_state.current_result.get("mode") == "Video Brain":
854
+ st.markdown("---")
855
+ st.markdown(f"**โ“ Q:** {st.session_state.current_result['query']}")
856
+ st.markdown(f"**๐Ÿ’ก A:** {st.session_state.current_result['data'].get('answer', '')}")
857
 
858
  # Show file uploader when icon is clicked
859
  if st.session_state.show_upload:
 
880
 
881
 
882
  # =====================================
883
+ # HANDLE SEARCH (Skip for Video Brain - it has its own UI)
884
  # =====================================
885
+ if submit and query.strip() and st.session_state.mode != "Video Brain":
886
  extra_data = None
887
  actual_query = query.strip()
888
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
889
  # For Product MVP mode, save to ideas history
890
  if st.session_state.mode == "Product MVP":
891
  st.session_state.product_ideas.append({