base-course-personalization / AdminDashboard.py
banao-tech's picture
Update AdminDashboard.py
e8f95c1 verified
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("<h1 style='color:#4F97FF;text-align:center;'>πŸ“Š Admin Dashboard</h1>", 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"""
<div style="background:#2D2D2D;padding:1.5rem;border-radius:12px;margin-bottom:1rem;border:1px solid #444;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;">
<h4 style="color:#4F97FF;margin:0;">πŸ“š {course['course_name']}</h4>
<span style="background:#10B981;color:black;padding:0.3rem 0.8rem;border-radius:15px;font-size:0.8rem;font-weight:bold;">COURSE ID: {course['course_id']}</span>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:1rem;">
<div>
<b>πŸ“Ή Total Videos:</b><br><span style="color:#E0E0E0;">{course['total_videos']}</span>
</div>
<div>
<b>🎯 Topic ID:</b><br><span style="color:#E0E0E0;">{course['topic_id']}</span>
</div>
<div>
<b>πŸ“– Chapter ID:</b><br><span style="color:#E0E0E0;">{course['chapter_id']}</span>
</div>
</div>
<div style="margin-top:1rem;">
<b>πŸ“… Created:</b> <span style="color:#888;">{course['created_at'][:19] if course['created_at'] != '-' else '-'}</span>
</div>
</div>
""", 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"""
<div style="background:#2D2D2D;padding:1.5rem;border-radius:12px;margin-bottom:1rem;border:1px solid #444;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;">
<h4 style="color:#4F97FF;margin:0;">🎬 {session['topic_title']}</h4>
<span style="background:{status_color};color:white;padding:0.3rem 0.8rem;border-radius:15px;font-size:0.8rem;font-weight:bold;">{session['status'].upper()}</span>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:1rem;">
<div>
<b>πŸ†” Session ID:</b><br><code style="background:#1A1A1A;padding:0.2rem;border-radius:4px;font-size:0.8rem;">{session['session_id'][:20]}...</code>
</div>
<div>
<b>πŸ“š Course ID:</b><br><span style="color:#E0E0E0;">{session['course_id']}</span>
</div>
<div>
<b>🎯 Topic ID:</b><br><span style="color:#E0E0E0;">{session['topic_id']}</span>
</div>
</div>
<div style="margin-top:1rem;display:flex;justify-content:space-between;">
<div><b>πŸ”§ Current Node:</b> <span style="color:#E0E0E0;">{session['node']}</span></div>
<div><b>⏱️ Updated:</b> <span style="color:#888;">{session['updated_at'][:19] if session['updated_at'] != '-' else '-'}</span></div>
</div>
{f"<div style='margin-top:1rem;'><b>πŸŽ₯ Video:</b> <a href='{session['video_url']}' target='_blank' style='color:#4F97FF;'>πŸ“Ί Watch Video</a></div>" if session['video_url'] else ""}
</div>
""", 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"""
<div style="background:#2D2D2D;padding:2rem;border-radius:12px;margin-bottom:2rem;border:1px solid #444;">
<h3 style="color:#4F97FF;margin-bottom:1rem;">πŸ“š {selected_course['course_name']}</h3>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:1rem;">
<div><b>πŸ†” Course ID:</b> {selected_course['course_id']}</div>
<div><b>πŸ“Ή Total Videos:</b> {selected_course['total_videos']}</div>
<div><b>πŸ“… Created:</b> {selected_course['created_at'][:19] if selected_course['created_at'] != '-' else '-'}</div>
</div>
</div>
""", 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"""
<div style="background:#1E1E1E;padding:1rem;border-radius:8px;margin-bottom:0.5rem;border-left:4px solid {status_color};">
<div style="display:flex;justify-content:between;align-items:center;">
<div style="flex:2;"><b>{session['topic_title']}</b></div>
<div style="flex:1;text-align:center;"><span style="background:{status_color};color:white;padding:0.2rem 0.6rem;border-radius:10px;font-size:0.75rem;">{session['status'].upper()}</span></div>
<div style="flex:1;text-align:right;color:#888;font-size:0.8rem;">{session['node']}</div>
</div>
{f"<div style='margin-top:0.5rem;'><a href='{session['video_url']}' target='_blank' style='color:#4F97FF;font-size:0.8rem;'>πŸŽ₯ Watch Video</a></div>" if session['video_url'] else ""}
</div>
""", unsafe_allow_html=True)
else:
st.info("No sessions found for this course yet.")