Download dashboards/student_db.py from FinEDProj/FInFront: direct link, hf CLI and curl.
- Browser
- Download file 8.61 kB
-
https://huggingface.co/spaces/FinEDProj/FInFront/resolve/main/dashboards/student_db.py
- Command line
-
hf download hf://spaces/FinEDProj/FInFront/dashboards/student_db.py
-
curl -L -o student_db.py https://huggingface.co/spaces/FinEDProj/FInFront/resolve/main/dashboards/student_db.py
8.61 kB
| import os | |
| import streamlit as st | |
| from phase.Student_view import chatbot, lesson, quiz | |
| from utils import db as dbapi | |
| import utils.api as api # <-- backend Space client | |
| USE_LOCAL_DB = os.getenv("DISABLE_DB", "1") != "1" | |
| # --- Load external CSS --- | |
| def load_css(file_name: str): | |
| try: | |
| with open(file_name, "r", encoding="utf-8") as f: | |
| st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True) | |
| except FileNotFoundError: | |
| st.warning("β οΈ Stylesheet not found. Please ensure 'assets/styles.css' exists.") | |
| def show_student_dashboard(): | |
| # Load CSS | |
| css_path = os.path.join("assets", "styles.css") | |
| load_css(css_path) | |
| # Current user | |
| user = st.session_state.user | |
| name = user["name"] | |
| student_id = user["user_id"] | |
| # --- Real metrics from DB --- | |
| # Requires helper funcs in utils/db.py: user_xp_and_level, recent_lessons_for_student, list_assignments_for_student | |
| if USE_LOCAL_DB and hasattr(dbapi, "user_xp_and_level"): | |
| stats = dbapi.user_xp_and_level(student_id) | |
| else: | |
| # Try backend; fall back to defaults if not available yet | |
| try: | |
| stats = api.user_stats(student_id) | |
| except Exception: | |
| stats = {"xp": 0, "level": 1, "streak": 0} | |
| xp = int(stats.get("xp", 0)) | |
| level = int(stats.get("level", 1)) | |
| study_streak = int(stats.get("streak", 0)) | |
| # # Cap for the visual bar | |
| # max_xp = max(500, ((xp // 500) + 1) * 500) | |
| # Assignments for βMy Workβ | |
| if USE_LOCAL_DB and hasattr(dbapi, "list_assignments_for_student"): | |
| rows = dbapi.list_assignments_for_student(student_id) | |
| else: | |
| try: | |
| rows = api.list_assignments_for_student(student_id) | |
| except Exception: | |
| rows = [] | |
| def _pct_from_row(r: dict): | |
| sp = r.get("score_pct") | |
| if sp is not None: | |
| try: | |
| return int(round(float(sp))) | |
| except Exception: | |
| pass | |
| s, t = r.get("score"), r.get("total") | |
| if s is not None and t not in (None, 0): | |
| try: | |
| return int(round((float(s) / float(t)) * 100)) | |
| except Exception: | |
| return None | |
| return None | |
| if USE_LOCAL_DB and hasattr(dbapi, "student_quiz_average"): | |
| quiz_score = dbapi.student_quiz_average(student_id) | |
| else: | |
| try: | |
| quiz_score = api.student_quiz_average(student_id) | |
| except Exception: | |
| quiz_score = 0 | |
| lessons_completed = sum(1 for r in rows if r.get("status") == "completed" or _pct_from_row(r) == 100) | |
| total_lessons = len(rows) | |
| # Recent lessons assigned to this student | |
| if USE_LOCAL_DB and hasattr(dbapi, "recent_lessons_for_student"): | |
| recent_lessons = dbapi.recent_lessons_for_student(student_id, limit=5) | |
| else: | |
| try: | |
| recent_lessons = api.recent_lessons_for_student(student_id, limit=5) | |
| except Exception: | |
| recent_lessons = [] | |
| # Daily Challenge derived from real data | |
| challenge_difficulty = "Easy" if level < 3 else ("Medium" if level < 6 else "Hard") | |
| challenge_title = "Complete 1 quiz with 80%+" | |
| challenge_desc = "Prove you remember yesterday's key points." | |
| challenge_progress = 100 if quiz_score >= 80 else 0 | |
| reward = "+50 XP" | |
| time_left = "Ends 11:59 PM" | |
| # Achievements from real data | |
| achievements = [ | |
| {"title": "First Steps", "desc": "Complete your first lesson", "earned": lessons_completed > 0}, | |
| {"title": "Quiz Whiz", "desc": "Score 80%+ on any quiz", "earned": quiz_score >= 80}, | |
| {"title": "On a Roll", "desc": "Study 3 days in a row", "earned": study_streak >= 3}, | |
| {"title": "Consistency", "desc": "Finish 5 assignments", "earned": total_lessons >= 5 and lessons_completed >= 5}, | |
| ] | |
| # --- Welcome Card --- | |
| st.markdown( | |
| f""" | |
| <div class="welcome-card"> | |
| <h2>Welcome back, {name}!</h2> | |
| <p style="font-size: 20px;">{"Ready to continue your financial journey?" if lessons_completed > 0 else "Start your financial journey."}</p> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| st.write("") | |
| # --- Quick Action Buttons --- | |
| actions = [ | |
| ("π Start a Lesson", "Lessons"), | |
| ("π Attempt a Quiz", "Quiz"), | |
| ("π¬ Talk to AI Tutor", "Chatbot"), | |
| ] | |
| # 5 columns: spacer, button, button, button, spacer | |
| cols = st.columns([1, 2, 2, 2, 1]) | |
| for i, (label, page) in enumerate(actions): | |
| with cols[i+1]: # skip the left spacer | |
| if st.button(label, key=f"action_{i}"): | |
| st.session_state.current_page = page | |
| st.rerun() | |
| st.write("") | |
| # --- Progress Summary Cards --- | |
| progress_cols = st.columns(3) | |
| progress_cols[0].metric("π Lessons Completed", f"{lessons_completed}/{total_lessons}") | |
| progress_cols[1].metric("π Quiz Score", f"{quiz_score}/100") | |
| progress_cols[2].metric("π₯ Study Streak", f"{study_streak} days") | |
| st.write("") | |
| # --- XP Bar --- | |
| # stats already fetched above | |
| xp = int(stats.get("xp", 0)) | |
| level = int(stats.get("level", 1)) | |
| study_streak = int(stats.get("streak", 0)) | |
| # prefer server-provided per-level fields | |
| into = int(stats.get("into", -1)) | |
| need = int(stats.get("need", -1)) | |
| # fallback if backend hasn't been updated to include into/need yet | |
| if into < 0 or need <= 0: | |
| base = 500 | |
| level = max(1, xp // base + 1) | |
| start = (level - 1) * base | |
| into = xp - start | |
| need = base | |
| if into == need: | |
| level += 1 | |
| into = 0 | |
| cap = max(500, ((xp // 500) + 1) * 500) # next threshold | |
| pct = 0 if cap <= 0 else min(100, int(round(100 * xp / cap))) | |
| st.markdown( | |
| f""" | |
| <div class="xp-card"> | |
| <span class="xp-level">Level {level}</span> | |
| <span class="xp-text">{xp:,} / {cap:,} XP</span> | |
| <div class="xp-bar"> | |
| <div class="xp-fill" style="width: {pct}%;"></div> | |
| </div> | |
| <div class="xp-total">Total XP: {xp:,}</div> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # pct = 0 if max_xp <= 0 else min(100, int(round((xp / max_xp) * 100))) | |
| # st.markdown( | |
| # f""" | |
| # <div class="xp-card"> | |
| # <span class="xp-level">Level {level}</span> | |
| # <span class="xp-text">{xp} / {max_xp} XP</span> | |
| # <div class="xp-bar"> | |
| # <div class="xp-fill" style="width: {pct}%;"></div> | |
| # </div> | |
| # </div> | |
| # """, | |
| # unsafe_allow_html=True | |
| # ) | |
| # st.write("") | |
| # --- My Assignments (from DB) --- | |
| st.markdown("---") | |
| st.subheader("π My Work") | |
| if not rows: | |
| st.info("No assignments yet. Ask your teacher to assign a lesson.") | |
| else: | |
| for a in rows: | |
| title = a.get("title", "Untitled") | |
| subj = a.get("subject", "General") | |
| lvl = a.get("level", "Beginner") | |
| status = a.get("status", "not_started") | |
| due = a.get("due_at") | |
| due_txt = f" Β· Due {str(due)[:10]}" if due else "" | |
| st.markdown(f"**{title}** Β· {subj} Β· {lvl}{due_txt}") | |
| st.caption(f"Status: {status} Β· Resume at section {a.get('current_pos', 1)}") | |
| st.markdown("---") | |
| # --- Recent Lessons & Achievements --- | |
| col1, col2 = st.columns(2) | |
| def _progress_value(v): | |
| try: | |
| f = float(v) | |
| except Exception: | |
| return 0.0 | |
| # streamlit accepts 0β1 float; if someone passes 0β100, scale it | |
| return max(0.0, min(1.0, f if f <= 1.0 else f / 100.0)) | |
| with col1: | |
| st.subheader("π Recent Lessons") | |
| st.caption("Continue where you left off") | |
| if not recent_lessons: | |
| st.info("No recent lessons yet.") | |
| else: | |
| for lesson in recent_lessons: | |
| prog = lesson.get("progress", 0) | |
| st.progress(_progress_value(prog)) | |
| status = "β Complete" if (isinstance(prog, (int, float)) and prog >= 100) else f"{int(prog)}% complete" | |
| st.write(f"**{lesson.get('title','Untitled Lesson')}** β {status}") | |
| with col2: | |
| st.subheader("π Achievements") | |
| st.caption("Your learning milestones") | |
| for ach in achievements: | |
| if ach["earned"]: | |
| st.success(f"β {ach['title']} β {ach['desc']}") | |
| else: | |
| st.info(f"π {ach['title']} β {ach['desc']}") | |