import streamlit as st import boto3 import time from datetime import datetime import os # DynamoDB configuration DYNAMODB_REGION = os.getenv("DYNAMODB_REGION", "ap-south-1") SESSION_TABLE = os.getenv("SESSION_TABLE", "SessionTracking") COURSE_TABLE = os.getenv("COURSE_TABLE", "CourseTracking") # AWS Configuration AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID") AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY") def fetch_courses(): """Fetch all courses from DynamoDB""" try: dynamodb = boto3.client( "dynamodb", region_name=DYNAMODB_REGION, aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY, ) response = dynamodb.scan(TableName=COURSE_TABLE) items = response.get("Items", []) courses = [] for item in items: course_detail = item.get("course_detail", {}).get("M", {}) courses.append({ "course_id": item.get("course_id", {}).get("N"), "course_name": item.get("course_name", {}).get("S"), "total_videos": item.get("total_videos", {}).get("N", "0"), "created_at": item.get("created_at", {}).get("S", "-"), "topic_id": course_detail.get("topic_id", {}).get("N", "-"), "chapter_id": course_detail.get("chapter_id", {}).get("N", "-"), }) return courses except Exception as e: st.error(f"⚠️ Error fetching courses: {e}") return [] def fetch_sessions(): """Fetch all sessions from DynamoDB""" try: dynamodb = boto3.client( "dynamodb", region_name=DYNAMODB_REGION, aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY, ) response = dynamodb.scan(TableName=SESSION_TABLE) items = response.get("Items", []) sessions = [] for item in items: sessions.append({ "session_id": item.get("session_id", {}).get("S"), "course_id": item.get("course_id", {}).get("N"), "topic_id": item.get("topic_id", {}).get("N"), "topic_title": item.get("topic_title", {}).get("S", "-"), "status": item.get("status", {}).get("S", "unknown"), "node": item.get("node", {}).get("S", "-"), "created_at": item.get("created_at", {}).get("S", "-"), "updated_at": item.get("updated_at", {}).get("S", "-"), "video_url": item.get("video_url", {}).get("S", None), }) return sessions except Exception as e: st.error(f"⚠️ Error fetching sessions: {e}") return [] def get_sessions_by_course(course_id): """Get sessions for a specific course""" all_sessions = fetch_sessions() return [session for session in all_sessions if session['course_id'] == str(course_id)] def render_admin_dashboard(): """Render the admin dashboard page""" st.markdown("

📊 Admin Dashboard

", unsafe_allow_html=True) # Auto-refresh controls col1, col2, col3 = st.columns([1, 1, 2]) with col1: if st.button("🔄 Refresh Now", key="manual_refresh"): st.rerun() with col2: auto_refresh = st.toggle("Auto Refresh (30s)", value=False) # Tabs for different views tab1, tab2, tab3 = st.tabs(["📚 Courses Overview", "🎬 Sessions Overview", "📈 Course Details"]) with tab1: render_courses_overview() with tab2: render_sessions_overview() with tab3: render_course_details() # Auto-refresh mechanism if auto_refresh: time.sleep(30) st.rerun() def render_courses_overview(): """Render courses overview tab""" st.markdown("### 📚 All Courses") courses = fetch_courses() if not courses: st.warning("No courses found yet.") st.info("Courses will appear here once you create them from the Course Generation page.") return # Display course count st.markdown(f"**Total Courses: {len(courses)}**") # Sort courses by created_at (newest first) try: courses.sort(key=lambda x: x['created_at'] if x['created_at'] != '-' else '1970-01-01', reverse=True) except: pass # Display courses in cards for i, course in enumerate(courses): with st.container(): st.markdown(f"""

📚 {course['course_name']}

COURSE ID: {course['course_id']}
📹 Total Videos:
{course['total_videos']}
🎯 Topic ID:
{course['topic_id']}
📖 Chapter ID:
{course['chapter_id']}
📅 Created: {course['created_at'][:19] if course['created_at'] != '-' else '-'}
""", unsafe_allow_html=True) def render_sessions_overview(): """Render sessions overview tab""" st.markdown("### 🎬 All Sessions") sessions = fetch_sessions() if not sessions: st.warning("No sessions found yet.") st.info("Sessions will appear here once you start generating courses.") return # Display session count and status summary col1, col2, col3, col4 = st.columns(4) status_counts = {} for session in sessions: status = session['status'].lower() status_counts[status] = status_counts.get(status, 0) + 1 with col1: st.metric("📊 Total Sessions", len(sessions)) with col2: completed = status_counts.get('completed', 0) st.metric("✅ Completed", completed) with col3: processing = status_counts.get('processing', 0) + status_counts.get('in_progress', 0) + status_counts.get('running', 0) st.metric("⏳ Processing", processing) with col4: failed = status_counts.get('failed', 0) + status_counts.get('error', 0) st.metric("❌ Failed", failed) # Sort sessions by updated_at (newest first) try: sessions.sort(key=lambda x: x['updated_at'] if x['updated_at'] != '-' else '1970-01-01', reverse=True) except: pass # Display sessions for i, session in enumerate(sessions): status_color = { 'completed': '#10B981', 'processing': '#F59E0B', 'in_progress': '#F59E0B', 'running': '#F59E0B', 'failed': '#EF4444', 'error': '#EF4444' }.get(session['status'].lower(), '#6B7280') with st.container(): st.markdown(f"""

🎬 {session['topic_title']}

{session['status'].upper()}
🆔 Session ID:
{session['session_id'][:20]}...
📚 Course ID:
{session['course_id']}
🎯 Topic ID:
{session['topic_id']}
🔧 Current Node: {session['node']}
⏱️ Updated: {session['updated_at'][:19] if session['updated_at'] != '-' else '-'}
{f"
🎥 Video: 📺 Watch Video
" if session['video_url'] else ""}
""", unsafe_allow_html=True) def render_course_details(): """Render detailed course view with sessions""" st.markdown("### 📈 Detailed Course View") courses = fetch_courses() if not courses: st.warning("No courses found.") return # Course selection course_options = {f"{course['course_name']} (ID: {course['course_id']})": course['course_id'] for course in courses} if course_options: selected_course_display = st.selectbox( "Select a course to view details:", options=list(course_options.keys()), key="course_detail_selector" ) selected_course_id = course_options[selected_course_display] selected_course = next(course for course in courses if course['course_id'] == str(selected_course_id)) # Display course information st.markdown(f"""

📚 {selected_course['course_name']}

🆔 Course ID: {selected_course['course_id']}
📹 Total Videos: {selected_course['total_videos']}
📅 Created: {selected_course['created_at'][:19] if selected_course['created_at'] != '-' else '-'}
""", unsafe_allow_html=True) # Get sessions for this course course_sessions = get_sessions_by_course(selected_course_id) if course_sessions: st.markdown(f"#### 🎬 Sessions for this Course ({len(course_sessions)} sessions)") # Session status summary for this course col1, col2, col3 = st.columns(3) course_status_counts = {} for session in course_sessions: status = session['status'].lower() course_status_counts[status] = course_status_counts.get(status, 0) + 1 with col1: completed = course_status_counts.get('completed', 0) st.metric("✅ Completed", completed) with col2: processing = course_status_counts.get('processing', 0) + course_status_counts.get('in_progress', 0) + course_status_counts.get('running', 0) st.metric("⏳ Processing", processing) with col3: failed = course_status_counts.get('failed', 0) + course_status_counts.get('error', 0) st.metric("❌ Failed", failed) # Display sessions in a table format for session in course_sessions: status_color = { 'completed': '#10B981', 'processing': '#F59E0B', 'in_progress': '#F59E0B', 'running': '#F59E0B', 'failed': '#EF4444', 'error': '#EF4444' }.get(session['status'].lower(), '#6B7280') st.markdown(f"""
{session['topic_title']}
{session['status'].upper()}
{session['node']}
{f"
🎥 Watch Video
" if session['video_url'] else ""}
""", unsafe_allow_html=True) else: st.info("No sessions found for this course yet.")