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"
" 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"
" if session['video_url'] else ""}
""", unsafe_allow_html=True)
else:
st.info("No sessions found for this course yet.")