#!/usr/bin/env python3 """ Test Script for Song Selection UI Demonstrates the new comprehensive song selection interface for Spark TikTok Analytics application This test script simulates the song selection workflow with sample data to validate the user experience design and functionality. """ import streamlit as st import pandas as pd from datetime import datetime, timedelta import numpy as np from dashboard_module import SparkDashboard # Configure Streamlit page st.set_page_config( page_title="Song Selection UI Test", page_icon="๐ŸŽต", layout="wide", initial_sidebar_state="expanded" ) def generate_sample_search_results(): """Generate sample Chartmetric search results for testing""" # Sample data that matches the expected structure sample_data = [ { 'ARTIST': 'Dua Lipa', 'TRACK': 'Physical', 'TIKTOK_TRACK_ID': 'Physical-Dua-Lipa-6889520563052645121', 'POSTS_LATEST': 15420, 'ACTIVE': True, 'CREATED_AT': datetime.now() - timedelta(days=30), 'MODIFIED_AT': datetime.now() - timedelta(days=1) }, { 'ARTIST': 'The Weeknd', 'TRACK': 'Blinding Lights', 'TIKTOK_TRACK_ID': 'Blinding-Lights-The-Weeknd-6845327847835265025', 'POSTS_LATEST': 28950, 'ACTIVE': True, 'CREATED_AT': datetime.now() - timedelta(days=45), 'MODIFIED_AT': datetime.now() - timedelta(days=2) }, { 'ARTIST': 'Olivia Rodrigo', 'TRACK': 'good 4 u', 'TIKTOK_TRACK_ID': 'good-4-u-Olivia-Rodrigo-6967234891234567890', 'POSTS_LATEST': 12340, 'ACTIVE': True, 'CREATED_AT': datetime.now() - timedelta(days=60), 'MODIFIED_AT': datetime.now() - timedelta(days=3) }, { 'ARTIST': 'Post Malone', 'TRACK': 'Circles', 'TIKTOK_TRACK_ID': 'Circles-Post-Malone-6756489123456789012', 'POSTS_LATEST': 8750, 'ACTIVE': True, 'CREATED_AT': datetime.now() - timedelta(days=90), 'MODIFIED_AT': datetime.now() - timedelta(days=5) }, { 'ARTIST': 'BTS', 'TRACK': 'Dynamite', 'TIKTOK_TRACK_ID': 'Dynamite-BTS-6889876543210987654', 'POSTS_LATEST': 45230, 'ACTIVE': True, 'CREATED_AT': datetime.now() - timedelta(days=120), 'MODIFIED_AT': datetime.now() - timedelta(days=1) }, { 'ARTIST': 'Billie Eilish', 'TRACK': 'bad guy', 'TIKTOK_TRACK_ID': 'bad-guy-Billie-Eilish-6734567890123456789', 'POSTS_LATEST': 890, 'ACTIVE': False, 'CREATED_AT': datetime.now() - timedelta(days=150), 'MODIFIED_AT': datetime.now() - timedelta(days=30) }, { 'ARTIST': 'Harry Styles', 'TRACK': 'Watermelon Sugar', 'TIKTOK_TRACK_ID': 'Watermelon-Sugar-Harry-Styles-6798765432109876543', 'POSTS_LATEST': 6540, 'ACTIVE': True, 'CREATED_AT': datetime.now() - timedelta(days=75), 'MODIFIED_AT': datetime.now() - timedelta(days=4) }, { 'ARTIST': 'Taylor Swift', 'TRACK': 'Anti-Hero', 'TIKTOK_TRACK_ID': 'Anti-Hero-Taylor-Swift-6912345678901234567', 'POSTS_LATEST': 32100, 'ACTIVE': True, 'CREATED_AT': datetime.now() - timedelta(days=20), 'MODIFIED_AT': datetime.now() - timedelta(hours=12) }, { 'ARTIST': 'Ed Sheeran', 'TRACK': 'Shape of You', 'TIKTOK_TRACK_ID': 'Shape-of-You-Ed-Sheeran-6678901234567890123', 'POSTS_LATEST': 450, 'ACTIVE': False, 'CREATED_AT': datetime.now() - timedelta(days=200), 'MODIFIED_AT': datetime.now() - timedelta(days=60) }, { 'ARTIST': 'Ariana Grande', 'TRACK': 'positions', 'TIKTOK_TRACK_ID': 'positions-Ariana-Grande-6845123456789012345', 'POSTS_LATEST': 18760, 'ACTIVE': True, 'CREATED_AT': datetime.now() - timedelta(days=35), 'MODIFIED_AT': datetime.now() - timedelta(days=2) } ] return pd.DataFrame(sample_data) def main(): """Main test application""" # Initialize dashboard dashboard = SparkDashboard() # App header st.title("๐ŸŽต Song Selection UI Test") st.markdown("**Testing the comprehensive song selection interface for Spark TikTok Analytics**") st.divider() # Sidebar with test information with st.sidebar: st.header("๐Ÿงช Test Information") st.markdown(""" **Testing Features:** - โœ… Multi-song selection with checkboxes - โœ… Select All / Clear All functionality - โœ… Active/Inactive song filtering - โœ… Song metrics display (posts count, status) - โœ… Scraping configuration options - โœ… Real-time selection summary - โœ… Estimated processing time - โœ… Professional UI layout """) st.markdown("---") st.markdown("**Sample Data:**") st.info("Using 10 sample songs with mixed active/inactive status and varying post counts") if st.button("๐Ÿ”„ Reset Test State"): # Clear session state for key in list(st.session_state.keys()): if key.startswith('song_'): del st.session_state[key] st.rerun() # Generate and display sample data info st.subheader("๐Ÿ“Š Test Setup") col1, col2, col3 = st.columns(3) with col1: st.metric("Sample Songs", "10") with col2: st.metric("Active Songs", "8") with col3: st.metric("Inactive Songs", "2") # Search simulation st.subheader("๐Ÿ” Simulated Search") search_col1, search_col2, search_col3 = st.columns(3) with search_col1: test_artist = st.text_input("Test Artist Search", value="", placeholder="e.g. Dua Lipa") with search_col2: test_track = st.text_input("Test Track Search", value="", placeholder="e.g. Physical") with search_col3: simulate_search = st.button("๐Ÿ” Simulate Search", type="primary") # Generate sample results sample_results = generate_sample_search_results() # Apply search filtering if specified filtered_results = sample_results.copy() if test_artist: filtered_results = filtered_results[ filtered_results['ARTIST'].str.contains(test_artist, case=False, na=False) ] if test_track: filtered_results = filtered_results[ filtered_results['TRACK'].str.contains(test_track, case=False, na=False) ] # Display the song selection interface st.markdown("---") if not filtered_results.empty: # Test the new song selection interface selection_result = dashboard.render_song_selection_table(filtered_results) # Handle selection result if selection_result: st.success("๐ŸŽ‰ Selection Processed Successfully!") # Display the return data structure st.subheader("๐Ÿ“‹ Returned Data Structure") with st.expander("๐Ÿ” View Selection Data", expanded=True): st.markdown("**Selected Songs:**") st.dataframe(selection_result['songs'], use_container_width=True) st.markdown("**Configuration:**") config_col1, config_col2 = st.columns(2) with config_col1: st.metric("Max Results per Song", selection_result['max_results']) with config_col2: st.metric("Include Thumbnails", "Yes" if selection_result['include_thumbnails'] else "No") st.markdown("**Summary:**") selected_count = len(selection_result['songs']) total_videos = selected_count * selection_result['max_results'] summary_col1, summary_col2, summary_col3 = st.columns(3) with summary_col1: st.metric("Songs Selected", selected_count) with summary_col2: st.metric("Total Videos to Scrape", f"{total_videos:,}") with summary_col3: cost_estimate = total_videos * 0.001 # Rough estimate st.metric("Est. API Cost", f"${cost_estimate:.2f}") # Show next steps st.markdown("### ๐Ÿš€ Next Steps") st.info(""" In the actual application, this data would be passed to: 1. **API Module** - To scrape TikTok videos using Apify 2. **Processing Module** - To process and clean video data 3. **Database Module** - To store videos and calculate analytics 4. **Dashboard** - To display real-time progress and results """) else: st.warning("No songs match your search criteria. Try different search terms.") # Footer information st.markdown("---") st.markdown("### ๐Ÿ—๏ธ Architecture Notes") st.markdown(""" **Professional UX Features Implemented:** - **Intuitive Selection**: Individual checkboxes with batch select/clear options - **Smart Filtering**: Show all, active only, or inactive only songs - **Visual Feedback**: Color-coded status indicators and post volume metrics - **Configuration Panel**: Appears only when songs are selected - **Real-time Estimates**: Processing time and video count predictions - **Selection Summary**: Clear overview of chosen songs before processing - **Session State Management**: Maintains selections across interactions - **Responsive Layout**: Professional column-based design - **Error Handling**: Graceful handling of missing data - **User Guidance**: Contextual help and instructions """) if __name__ == "__main__": main()