userIdc2024 commited on
Commit
5c05394
·
verified ·
1 Parent(s): c531990

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +296 -1
src/streamlit_app.py CHANGED
@@ -468,4 +468,299 @@ def display_timestamp_improvements(json_data):
468
  column_config={
469
  "Timestamp": st.column_config.TextColumn(width="small"),
470
  "Current Element": st.column_config.TextColumn(width="medium"),
471
- "Improvement Type": st.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  column_config={
469
  "Timestamp": st.column_config.TextColumn(width="small"),
470
  "Current Element": st.column_config.TextColumn(width="medium"),
471
+ "Improvement Type": st.column_config.TextColumn(width="medium"),
472
+ "Recommended Change": st.column_config.TextColumn(width="large"),
473
+ "Expected Impact": st.column_config.TextColumn(width="medium"),
474
+ "Priority": st.column_config.TextColumn(width="small")
475
+ }
476
+ )
477
+
478
+ logger.info("Timestamp improvements displayed successfully")
479
+
480
+ except Exception as e:
481
+ error_msg = f"Error displaying timestamp improvements: {str(e)}"
482
+ logger.error(error_msg, exc_info=True)
483
+ st.error(error_msg)
484
+
485
+ def create_csv_download(json_data):
486
+ """Create CSV content with all scripts combined"""
487
+ logger.info("Creating CSV download...")
488
+
489
+ try:
490
+ all_scripts_data = []
491
+
492
+ # Combine all script variations into one dataset
493
+ for i, variation in enumerate(json_data.get("script_variations", []), 1):
494
+ variation_name = variation.get("variation_name", f"Variation {i}")
495
+ logger.debug(f"Processing variation for CSV: {variation_name}")
496
+
497
+ for row in variation.get("script_table", []):
498
+ script_row = {
499
+ 'Variation': variation_name,
500
+ 'Timestamp': row.get('timestamp', ''),
501
+ 'Script_Voiceover': row.get('script_voiceover', ''),
502
+ 'Visual_Direction': row.get('visual_direction', ''),
503
+ 'Psychological_Trigger': row.get('psychological_trigger', ''),
504
+ 'CTA_Action': row.get('cta_action', '')
505
+ }
506
+ all_scripts_data.append(script_row)
507
+
508
+ # Convert to DataFrame and then to CSV
509
+ if all_scripts_data:
510
+ df = pd.DataFrame(all_scripts_data)
511
+ csv_content = df.to_csv(index=False)
512
+ logger.info(f"CSV created successfully with {len(all_scripts_data)} rows")
513
+ return csv_content
514
+ else:
515
+ logger.warning("No script data available for CSV")
516
+ return "No script data available"
517
+
518
+ except Exception as e:
519
+ error_msg = f"Error creating CSV: {str(e)}"
520
+ logger.error(error_msg, exc_info=True)
521
+ return f"Error creating CSV: {error_msg}"
522
+
523
+ def check_token(user_token):
524
+ logger.info("Checking access token...")
525
+
526
+ ACCESS_TOKEN = os.getenv("ACCESS_TOKEN")
527
+ if not ACCESS_TOKEN:
528
+ error_msg = "ACCESS_TOKEN not set in environment."
529
+ logger.critical(error_msg)
530
+ return False, "Server error: Access token not configured."
531
+
532
+ if user_token == ACCESS_TOKEN:
533
+ logger.info("Access token validated successfully.")
534
+ return True, ""
535
+
536
+ logger.warning("Invalid access token attempt.")
537
+ return False, "Invalid token."
538
+
539
+ def main():
540
+ """Main application function"""
541
+ logger.info("Starting main application...")
542
+
543
+ if "authenticated" not in st.session_state:
544
+ st.session_state["authenticated"] = False
545
+ logger.debug("Authentication state initialized")
546
+
547
+ if not st.session_state["authenticated"]:
548
+ logger.info("User not authenticated, showing login screen")
549
+ st.markdown("## Access Required")
550
+ token_input = st.text_input("Enter Access Token", type="password")
551
+ if st.button("Unlock App"):
552
+ ok, error_msg = check_token(token_input)
553
+ if ok:
554
+ st.session_state["authenticated"] = True
555
+ logger.info("User authenticated successfully")
556
+ st.rerun()
557
+ else:
558
+ logger.warning(f"Authentication failed: {error_msg}")
559
+ st.error(error_msg)
560
+ return
561
+
562
+ # Add API test button for debugging
563
+ if st.sidebar.button("🔧 Test API Connection"):
564
+ logger.info("Testing API connection...")
565
+ try:
566
+ genai.configure(api_key=GEMINI_API_KEY)
567
+ models = list(genai.list_models())
568
+ st.sidebar.success(f"✅ API Working! Found {len(models)} models")
569
+ logger.info(f"API test successful, found {len(models)} models")
570
+ for model in models[:3]: # Show first 3 models
571
+ st.sidebar.text(f"• {model.name}")
572
+ except Exception as e:
573
+ error_msg = f"❌ API Test Failed: {str(e)}"
574
+ st.sidebar.error(error_msg)
575
+ logger.error(f"API test failed: {str(e)}", exc_info=True)
576
+
577
+ # Sidebar navigation
578
+ if st.session_state["authenticated"]:
579
+ logger.info("User authenticated, showing main interface")
580
+
581
+ selected_tab = st.sidebar.radio("Select Mode", ["Script Generator", "History"])
582
+ logger.debug(f"Selected tab: {selected_tab}")
583
+
584
+ # ========== SCRIPT GENERATOR ==========
585
+ if selected_tab == "Script Generator":
586
+ logger.info("Script Generator mode selected")
587
+
588
+ with st.expander("How to Use This Tool", expanded=False):
589
+ st.markdown("""
590
+ ### Upload Guidelines:
591
+ - **Best videos to analyze**: Already profitable Facebook/TikTok ads in your niche
592
+ - **Video length**: 30–90 seconds work best for analysis
593
+ - **Quality**: Clear audio and visuals help with better analysis
594
+
595
+ ### Context Tips:
596
+ - **Offer details**: Be specific about your main promise and mechanism
597
+ - **Audience**: Include demographics, pain points, and desires
598
+ - **Hooks**: Mention any specific angles that have worked for you
599
+
600
+ ### Script Optimization:
601
+ - Generated scripts focus on stopping scroll and driving clicks
602
+ - Each variation tests different psychological triggers
603
+ - Use the timestamp format for precise video production
604
+ - Test multiple variations to find your best performer
605
+ """)
606
+ st.subheader("Input Configuration")
607
+
608
+ uploaded_video = st.file_uploader(
609
+ "Upload Reference Video",
610
+ type=['mp4', 'mov', 'avi', 'mkv'],
611
+ help="Upload a profitable ad video to analyze and create variations from"
612
+ )
613
+
614
+ if uploaded_video is not None:
615
+ logger.info(f"Video uploaded: {uploaded_video.name}, size: {uploaded_video.size} bytes")
616
+ else:
617
+ st.info("Please upload a reference video to begin analysis.")
618
+
619
+ st.subheader("Additional Context (Optional)")
620
+
621
+ offer_details = st.text_area(
622
+ "Offer Details",
623
+ placeholder="e.g., Solar installation with $0 down payment...",
624
+ height=80,
625
+ help="Describe the product/service and main promise"
626
+ )
627
+
628
+ target_audience = st.text_area(
629
+ "Target Audience",
630
+ placeholder="e.g., 40+ homeowners with high electricity bills...",
631
+ height=80,
632
+ help="Describe the ideal customer demographics and pain points"
633
+ )
634
+
635
+ specific_hooks = st.text_area(
636
+ "Specific Hooks to Test",
637
+ placeholder="e.g., Government rebate angle, celebrity endorsement...",
638
+ height=80,
639
+ help="Any specific angles or hooks you want to incorporate"
640
+ )
641
+
642
+ additional_context = st.text_area(
643
+ "Additional Context",
644
+ placeholder="Any other relevant information...",
645
+ height=100,
646
+ help="Compliance requirements, brand guidelines, or other notes"
647
+ )
648
+
649
+ generate_button = st.button("Generate Script Variations", use_container_width=True)
650
+
651
+ if "analysis_results" in st.session_state and st.session_state["analysis_results"]:
652
+ if st.button("Clear Results", use_container_width=True):
653
+ del st.session_state["analysis_results"]
654
+ logger.info("Analysis results cleared")
655
+ st.rerun()
656
+
657
+ # Generate & show results
658
+ if uploaded_video and generate_button:
659
+ logger.info("Starting video analysis process...")
660
+
661
+ with st.spinner("Analyzing video and generating scripts..."):
662
+ video_bytes = uploaded_video.read()
663
+ uploaded_video.seek(0)
664
+
665
+ json_response = analyze_video_and_generate_script(
666
+ video_bytes,
667
+ uploaded_video.name,
668
+ offer_details,
669
+ target_audience,
670
+ specific_hooks,
671
+ additional_context
672
+ )
673
+
674
+ if json_response:
675
+ logger.info("Analysis completed successfully, saving to database...")
676
+ try:
677
+ insert_analysis_result(
678
+ video_name=uploaded_video.name,
679
+ offer_details=offer_details,
680
+ target_audience=target_audience,
681
+ specific_hook=specific_hooks,
682
+ additional_context=additional_context,
683
+ response=json_response
684
+ )
685
+ logger.info("Results saved to database")
686
+ except Exception as db_error:
687
+ logger.error(f"Failed to save to database: {str(db_error)}", exc_info=True)
688
+ st.warning("Analysis completed but failed to save to database")
689
+
690
+ st.session_state["analysis_results"] = json_response
691
+ else:
692
+ logger.error("Analysis failed, no response received")
693
+
694
+ if "analysis_results" in st.session_state:
695
+ logger.info("Displaying analysis results...")
696
+ json_response = st.session_state["analysis_results"]
697
+
698
+ tab1, tab2, tab3 = st.tabs(["Script Variations", "Video Analysis", "Improvement Recommendations"])
699
+
700
+ with tab1:
701
+ display_script_variations(json_response)
702
+ csv_content = create_csv_download(json_response)
703
+ st.download_button("Download All Scripts (CSV)", data=csv_content,
704
+ file_name="video_script_variations.csv", mime="text/csv")
705
+ with tab2:
706
+ display_video_analysis(json_response)
707
+ with tab3:
708
+ display_timestamp_improvements(json_response)
709
+
710
+ # ========== HISTORY ==========
711
+ elif selected_tab == "History":
712
+ logger.info("History mode selected")
713
+
714
+ try:
715
+ from database import get_all_results
716
+ history_items = get_all_results(limit=20)
717
+ logger.info(f"Retrieved {len(history_items) if history_items else 0} history items")
718
+
719
+ if history_items:
720
+ video_titles = [
721
+ f"{item['video_name']} ({item['created_at'].strftime('%Y-%m-%d %H:%M')})"
722
+ for item in history_items
723
+ ]
724
+
725
+ selected = st.sidebar.radio("History Items", video_titles, index=0)
726
+ selected_index = video_titles.index(selected)
727
+ selected_data = history_items[selected_index]
728
+
729
+ logger.info(f"Selected history item: {selected_data['video_name']}")
730
+
731
+ st.subheader(f"Analysis for: {selected_data['video_name']}")
732
+ json_response = selected_data.get("response")
733
+
734
+ if json_response:
735
+ tab1, tab2, tab3 = st.tabs(["Script Variations", "Video Analysis", "Improvement Recommendations"])
736
+
737
+ with tab1:
738
+ display_script_variations(json_response)
739
+ with tab2:
740
+ display_video_analysis(json_response)
741
+ with tab3:
742
+ display_timestamp_improvements(json_response)
743
+ else:
744
+ warning_msg = "No valid response data for this analysis."
745
+ logger.warning(warning_msg)
746
+ st.warning(warning_msg)
747
+ else:
748
+ logger.info("No history items found")
749
+ st.sidebar.info("No saved analyses found.")
750
+ st.info("No saved history available.")
751
+
752
+ except Exception as history_error:
753
+ error_msg = f"Error loading history: {str(history_error)}"
754
+ logger.error(error_msg, exc_info=True)
755
+ st.error(error_msg)
756
+
757
+ if __name__ == "__main__":
758
+ try:
759
+ logger.info("=" * 50)
760
+ logger.info("LAUNCHING VIDEO ANALYZER APPLICATION")
761
+ logger.info("=" * 50)
762
+ main()
763
+ except Exception as e:
764
+ logger.exception("CRITICAL ERROR: Unhandled error during app launch")
765
+ st.error(f"Critical application error: {str(e)}")
766
+ st.error("Please check the logs for more details.")