From 36af35b4bb08900dc0e71455a68d1a4a53d21c42 Mon Sep 17 00:00:00 2001 From: Yash Bahadure Date: Mon, 20 Oct 2025 22:02:15 +0530 Subject: [PATCH 1/2] Add files via upload The above file was made in order to help teacher to analyze about there daily effectiveness which will provide data analysis by learning different machine learning models. Currently its not fully functional on its own but the project is undergo currently. --- Domains/AI-ML/app.py | 530 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 530 insertions(+) create mode 100644 Domains/AI-ML/app.py diff --git a/Domains/AI-ML/app.py b/Domains/AI-ML/app.py new file mode 100644 index 00000000..a096b468 --- /dev/null +++ b/Domains/AI-ML/app.py @@ -0,0 +1,530 @@ +import streamlit as st +import pandas as pd +import numpy as np +import plotly.express as px +import plotly.graph_objects as go +import datetime +import os + +# Add these imports for PDF export +import io +try: + import pdfkit +except ImportError: + pdfkit = None + +# Optional: Uncomment if you want to use OpenAI for dynamic chat responses +# import openai + +# --------------------------------------- +# 🌐 PAGE CONFIG +# --------------------------------------- +st.set_page_config( + page_title="Faculty Effectiveness Analyzer", + page_icon="📊", + layout="wide", + initial_sidebar_state="collapsed" +) + +# --------------------------------------- +# 👩‍🏫 FACULTY DATA (with manual add section) +# --------------------------------------- +def save_faculty_profiles(profiles): + pd.DataFrame(profiles).to_json("faculty_profiles.json") + +def load_faculty_profiles(): + if os.path.exists("faculty_profiles.json"): + return pd.read_json("faculty_profiles.json", typ='dict') + else: + return None + +profiles_from_file = load_faculty_profiles() +if profiles_from_file: + faculty_profiles = profiles_from_file +else: + faculty_profiles = { + "Dr. John Doe": { + "image": "https://cdn-icons-png.flaticon.com/512/3135/3135715.png", + "rating": "4.8 / 5", + "experience": "12 Years", + "designation": "Associate Professor", + "department": "Computer Engineering", + "institution": "ABC Institute of Technology", + "about": "Passionate about building real-world technical skills and improving student outcomes through interactive learning.", + "expertise": ["Machine Learning", "HCI", "Operating Systems"], + "email": "johndoe@abc.edu", + "id": "CSE-1023", + "achievements": [ + "Best Teacher Award 2022", + "Published 10+ research papers", + "Invited Speaker at MLConf 2024" + ] + }, + "Prof. Meera Sharma": { + "image": "https://cdn-icons-png.flaticon.com/512/4140/4140048.png", + "rating": "4.5 / 5", + "experience": "8 Years", + "designation": "Assistant Professor", + "department": "Information Technology", + "institution": "XYZ College of Engineering", + "about": "Focused on student engagement and improving conceptual understanding.", + "expertise": ["Cloud Computing", "IoT", "Networking"], + "email": "meerasharma@xyz.edu", + "id": "IT-1122", + "achievements": [ + "Young Researcher Award 2021", + "Organized IoT Symposium 2023" + ] + }, + "Dr. A. Sharma": { + "image": "https://cdn-icons-png.flaticon.com/512/4140/4140037.png", + "rating": "4.9 / 5", + "experience": "15 Years", + "designation": "Professor", + "department": "AI & Data Science", + "institution": "Global Tech University", + "about": "Known for delivering complex topics with clarity and adaptive teaching methods.", + "expertise": ["AI", "Data Science", "Deep Learning"], + "email": "asharma@gtu.edu", + "id": "AIDS-1007", + "achievements": [ + "AI Excellence Award 2023", + "Published 20+ journal articles" + ] + } + } + +# --------------------------------------- +# SIDEBAR: Manual Faculty Add Section +# --------------------------------------- +st.sidebar.markdown("### ➕ Add New Faculty Profile") +with st.sidebar.form("add_faculty_form"): + new_name = st.text_input("Full Name") + new_email = st.text_input("Email") + new_id = st.text_input("Faculty ID") + new_designation = st.text_input("Designation") + new_department = st.text_input("Department") + new_institution = st.text_input("Institution") + new_experience = st.text_input("Experience (e.g. 5 Years)") + new_rating = st.text_input("Rating (e.g. 4.5 / 5)") + new_about = st.text_area("About") + new_expertise = st.text_input("Expertise (comma separated)") + new_image = st.text_input("Image URL (optional)", value="https://cdn-icons-png.flaticon.com/512/3135/3135715.png") + new_achievements = st.text_area("Achievements (one per line)") + add_faculty_btn = st.form_submit_button("Add Faculty") + + if add_faculty_btn and new_name: + faculty_profiles[new_name] = { + "image": new_image, + "rating": new_rating, + "experience": new_experience, + "designation": new_designation, + "department": new_department, + "institution": new_institution, + "about": new_about, + "expertise": [e.strip() for e in new_expertise.split(",") if e.strip()], + "email": new_email, + "id": new_id, + "achievements": [a.strip() for a in new_achievements.split("\n") if a.strip()] + } + save_faculty_profiles(faculty_profiles) + st.sidebar.success(f"Faculty '{new_name}' added! Please refresh to see in the list.") + +selected_faculty = st.sidebar.selectbox("👩‍🏫 Select Faculty", list(faculty_profiles.keys())) +faculty = faculty_profiles[selected_faculty] + +# --------------------------------------- +# 🧠 SIMULATED DATA GENERATION (PER FACULTY) +# --------------------------------------- +def generate_day(seed): + np.random.seed(seed) + activities = ['Instruction', 'Research', 'Admin', 'Email', 'Prep', 'Meeting', 'Break', 'Mentoring'] + hours = np.random.choice(range(9, 18), 10) + return pd.DataFrame({ + 'timestamp': [f"{h:02d}:00:00" for h in hours], + 'activity_type': np.random.choice(activities, 10), + 'duration_minutes': np.random.randint(15, 120, 10), + 'tcl_score': np.random.randint(10, 100, 10), + 'context_switch_flag': np.random.choice([0, 1], 10) + }) + +base_date = datetime.date(2025, 10, 13) +faculty_data = {f: {base_date - datetime.timedelta(days=i): generate_day(i+idx*10) for i in range(30)} + for idx, f in enumerate(faculty_profiles.keys())} + +# --------------------------------------- +# 📄 FACULTY PROFILE (Sliding Panel) +# --------------------------------------- +with st.expander(f"👨‍🏫 Faculty Profile: {selected_faculty}", expanded=True): + colA, colB = st.columns([1, 2]) + with colA: + st.image(faculty['image'], width=140) + st.metric("⭐ Rating", faculty['rating']) + st.metric("🏫 Experience", faculty['experience']) + with colB: + st.write(f"**Designation:** {faculty['designation']}") + st.write(f"**Department:** {faculty['department']}") + st.write(f"**Institution:** {faculty['institution']}") + st.write(f"**Email:** {faculty['email']} | **Faculty ID:** {faculty['id']}") + st.write(f"**Expertise:** {', '.join(faculty['expertise'])}") + st.write(f"📝 {faculty['about']}") + # Achievements Section + if "achievements" in faculty: + st.markdown("**🏆 Achievements:**") + for ach in faculty["achievements"]: + st.markdown(f"- {ach}") + +# --------------------------------------- +# 🗓 PERIOD SELECTION +# --------------------------------------- +st.title("📊 Advanced Faculty Effectiveness & Workload Analytics Dashboard") +period = st.radio("Select Analysis Period:", ["Daily", "Weekly", "Monthly"], horizontal=True) + +if period == "Daily": + selected_date = st.date_input("Select Date", base_date) + df = faculty_data[selected_faculty].get(selected_date, pd.DataFrame()) +elif period == "Weekly": + dates = sorted(faculty_data[selected_faculty].keys())[:7] + df = pd.concat([faculty_data[selected_faculty][d] for d in dates], keys=dates).reset_index(level=1, drop=True).rename_axis('date').reset_index() +else: + dates = sorted(faculty_data[selected_faculty].keys()) + df = pd.concat([faculty_data[selected_faculty][d] for d in dates], keys=dates).reset_index(level=1, drop=True).rename_axis('date').reset_index() + +if df.empty: + st.warning("No data found.") + st.stop() + +# --------------------------------------- +# 🧮 METRICS COMPUTATION +# --------------------------------------- +df['hour'] = pd.to_datetime(df['timestamp']).dt.hour +time_allocation = df.groupby('activity_type')['duration_minutes'].sum() +wasted_time = df['context_switch_flag'].sum() * 5 +high_load_time = df[df['tcl_score'] > 70]['duration_minutes'].sum() +avg_tcl = df['tcl_score'].mean() +peak_hour = df.groupby('hour')['tcl_score'].mean().idxmax() + +# Work-Life Balance Indicator +break_time = df[df['activity_type'] == 'Break']['duration_minutes'].sum() +work_time = df['duration_minutes'].sum() +balance_score = (break_time / work_time) * 100 if work_time else 0 + +# --------------------------------------- +# Utility: Save manual entries to CSV for persistent storage +# --------------------------------------- +def save_manual_entries(faculty_name, manual_entries): + df_manual = pd.DataFrame(manual_entries) + filename = f"{faculty_name.replace(' ', '_')}_manual_entries.csv" + df_manual.to_csv(filename, index=False) + return filename + +def load_manual_entries(faculty_name): + filename = f"{faculty_name.replace(' ', '_')}_manual_entries.csv" + try: + return pd.read_csv(filename).to_dict('records') + except Exception: + return [] + +# --------------------------------------- +# ⏱ GAUGE CHART FOR TCL +# --------------------------------------- +fig_gauge = go.Figure(go.Indicator( + mode="gauge+number", + value=avg_tcl, + title={'text': "Real-Time TCL"}, + gauge={'axis': {'range': [0, 100]}, + 'bar': {'color': "red" if avg_tcl > 70 else "green"}, + 'steps': [ + {'range': [0, 50], 'color': "lightgreen"}, + {'range': [50, 80], 'color': "orange"}, + {'range': [80, 100], 'color': "red"}]} +)) +st.plotly_chart(fig_gauge, use_container_width=True) + +# --------------------------------------- +# 🧭 KEY INDICATORS +# --------------------------------------- +k1, k2, k3, k4, k5 = st.columns(5) +k1.metric("🧠 Average TCL", f"{avg_tcl:.1f}/100") +k2.metric("⏳ Context Switch Time Wasted", f"{wasted_time} min") +k3.metric("🔥 High Load Duration", f"{high_load_time} min") +k4.metric("🕒 Peak Load Hour", f"{peak_hour}:00") +k5.metric("⚖️ Work-Life Balance", f"{balance_score:.1f}%") + +st.markdown("---") + +# --------------------------------------- +# 📊 TABS STRUCTURE +# --------------------------------------- +tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8 = st.tabs([ + "📌 Activity Overview", + "📈 Trends & Graphs", + "🤖 AI Insights", + "📊 Advanced Analytics", + "📥 Reports", + "🧑‍💻 Virtual Assistant", + "✍️ Manual Entry", + "🔬 Data Science & ML" +]) + +# --------------------------------------- +# 📌 TAB 1: ACTIVITY OVERVIEW +# --------------------------------------- +with tab1: + col1, col2 = st.columns(2) + with col1: + fig = px.pie(values=time_allocation.values, names=time_allocation.index, + hole=0.4, color_discrete_sequence=px.colors.sequential.Viridis, + title="🕒 Time Allocation by Activity") + fig.update_traces(textinfo='percent+label') + st.plotly_chart(fig, use_container_width=True) + + with col2: + df_treemap = df.groupby('activity_type')['tcl_score'].mean().reset_index() + fig_tree = px.treemap(df_treemap, path=['activity_type'], values='tcl_score', + color='tcl_score', color_continuous_scale='Blues', + title="🌳 Activity Cognitive Load Tree") + st.plotly_chart(fig_tree, use_container_width=True) + +# --------------------------------------- +# 📈 TAB 2: TRENDS & GRAPHS +# --------------------------------------- +with tab2: + if period == "Daily": + hourly_avg = df.groupby('hour')['tcl_score'].mean().reset_index() + st.subheader("📅 Hourly Cognitive Load Trend") + st.plotly_chart(px.line(hourly_avg, x='hour', y='tcl_score', markers=True, title="Hourly TCL Curve"), use_container_width=True) + else: + st.subheader(f"📆 {period} Trends") + trend_tcl = df.groupby('date')['tcl_score'].mean().reset_index() + trend_time = df.groupby('date')['duration_minutes'].sum().reset_index() + c1, c2 = st.columns(2) + with c1: + st.plotly_chart(px.line(trend_tcl, x='date', y='tcl_score', title="📈 Avg TCL over time", markers=True), use_container_width=True) + with c2: + st.plotly_chart(px.bar(trend_time, x='date', y='duration_minutes', title="⏳ Total Workload per Day"), use_container_width=True) + +# --------------------------------------- +# 🧠 TAB 3: AI INSIGHTS +# --------------------------------------- +with tab3: + st.subheader("🤖 AI-Powered Efficiency Insights") + insights = [] + if wasted_time > 30: + insights.append(f"⚠️ High context switching detected: {wasted_time} minutes wasted. Batch administrative work at the end of the day.") + if high_load_time > 120: + insights.append("🔥 High cognitive load period exceeded 2 hours. Introduce structured breaks.") + if avg_tcl < 40: + insights.append("📉 TCL below expected average. Increase interactive sessions.") + if avg_tcl > 80: + insights.append("🧠 Exceptional focus periods detected. Schedule complex lectures during these hours.") + if balance_score < 5: + insights.append("⚖️ Work-life balance is low. Encourage more breaks.") + if not insights: + st.success("🎉 Excellent balance detected. No major issues found.") + else: + for ins in insights: + st.info(ins) + +# --------------------------------------- +# 📊 TAB 4: ADVANCED ANALYTICS +# --------------------------------------- +with tab4: + st.subheader("📊 Activity vs Cognitive Load Scatter Analysis") + fig_scatter = px.scatter( + df, x='duration_minutes', y='tcl_score', color='activity_type', + size='duration_minutes', hover_data=['timestamp'], + title="⏳ Duration vs 🧠 TCL Score Scatter" + ) + st.plotly_chart(fig_scatter, use_container_width=True) + + st.subheader("🔸 Load Distribution Heatmap") + df_heat = df.pivot_table(index='activity_type', columns='hour', values='tcl_score', aggfunc='mean') + fig_heat = go.Figure(data=go.Heatmap(z=df_heat.values, x=df_heat.columns, y=df_heat.index, colorscale='Reds')) + fig_heat.update_layout(title="Heatmap of Cognitive Load by Hour & Activity", xaxis_nticks=12) + st.plotly_chart(fig_heat, use_container_width=True) + +# --------------------------------------- +# 📥 TAB 5: REPORTS +# --------------------------------------- +with tab5: + st.subheader("📤 Generate & Download Report") + st.dataframe(df) + total_duration = df['duration_minutes'].sum() / 60 + st.markdown(f"🕒 **Total Hours Worked:** {total_duration:.2f} hrs") + st.markdown(f"📌 **Distinct Activities:** {df['activity_type'].nunique()}") + st.download_button( + label="📥 Download CSV Report", + data=df.to_csv(index=False).encode('utf-8'), + file_name=f"{selected_faculty}_{period.lower()}_report.csv", + mime='text/csv' + ) + # PDF Export Option + if pdfkit: + html = df.to_html(index=False) + pdf_bytes = pdfkit.from_string(html, False) + st.download_button( + label="📄 Download PDF Report", + data=pdf_bytes, + file_name=f"{selected_faculty}_{period.lower()}_report.pdf", + mime='application/pdf' + ) + else: + st.info("PDF export requires `pdfkit` and `wkhtmltopdf` installed. Run `pip install pdfkit` and download wkhtmltopdf from https://wkhtmltopdf.org/downloads.html") + +# --------------------------------------- +# 🧑‍💻 TAB 6: VIRTUAL ASSISTANT (Dynamic Chat) +# --------------------------------------- +with tab6: + st.markdown("## 💬 Faculty Virtual Assistant") + st.write("Ask about your schedule, workload, breaks, or cognitive load. Example: *How busy am I today?*") + + if "chat_history" not in st.session_state: + st.session_state.chat_history = [] + + user_query = st.chat_input("Type your question here...") + + def get_dynamic_response(query): + context = ( + f"Faculty: {selected_faculty}\n" + f"Total work time: {work_time:.1f} minutes\n" + f"Break time: {break_time:.1f} minutes\n" + f"Work-life balance score: {balance_score:.1f}%\n" + f"Average TCL: {avg_tcl:.1f}/100\n" + f"High load duration: {high_load_time} minutes\n" + f"Context switch time wasted: {wasted_time} minutes\n" + f"Peak busy hour: {peak_hour}:00\n" + f"Distinct activities: {df['activity_type'].nunique()}\n" + ) + prompt = ( + f"You are a helpful assistant for faculty workload analytics. " + f"Here is the faculty's current dashboard data:\n{context}\n" + f"User question: {query}\n" + f"Answer in a friendly, concise way using the data above." + ) + # Uncomment below to use OpenAI + # try: + # response = openai.ChatCompletion.create( + # model="gpt-3.5-turbo", + # messages=[ + # {"role": "system", "content": "You are a helpful assistant for faculty workload analytics."}, + # {"role": "user", "content": prompt} + # ], + # max_tokens=150 + # ) + # return response.choices[0].message.content.strip() + # except Exception as e: + # return f"Sorry, I couldn't fetch a response. ({e})" + # --- Fallback: Static rule-based response --- + query = query.lower() + if "busy" in query or "schedule" in query: + return f"You have worked a total of {work_time:.1f} minutes today. Peak busy hour: {peak_hour}:00." + elif "break" in query or "rest" in query: + return f"You took {break_time:.1f} minutes of break today. Work-life balance score: {balance_score:.1f}%." + elif "tcl" in query or "load" in query: + return f"Your average TCL is {avg_tcl:.1f}/100. High load duration: {high_load_time} minutes." + elif "context switch" in query or "distraction" in query: + return f"Context switching wasted {wasted_time} minutes today. Try batching similar tasks." + elif "activities" in query: + return f"Distinct activities performed: {df['activity_type'].nunique()}." + elif "report" in query or "download" in query: + return "You can download your report from the 'Reports' tab." + else: + return "I'm here to help! Ask about your workload, schedule, breaks, or cognitive load." + + if user_query: + st.session_state.chat_history.append(("user", user_query)) + response = get_dynamic_response(user_query) + st.session_state.chat_history.append(("assistant", response)) + + for role, msg in st.session_state.chat_history: + st.chat_message(role).write(msg) + +# --------------------------------------- +# ✍️ TAB 7: MANUAL ENTRY (with persistent storage) +# --------------------------------------- +with tab7: + st.subheader("✍️ Add Your Own Experience Data") + st.write("Manually log your activities, workload, or notes for today. Entries will be saved and used for analytics.") + + if "manual_entries" not in st.session_state: + st.session_state.manual_entries = load_manual_entries(selected_faculty) + + with st.form("manual_entry_form"): + activity = st.selectbox("Activity Type", ['Instruction', 'Research', 'Admin', 'Email', 'Prep', 'Meeting', 'Break', 'Mentoring', 'Other']) + duration = st.number_input("Duration (minutes)", min_value=1, max_value=480, value=60) + tcl = st.slider("TCL Score (1-100)", min_value=1, max_value=100, value=50) + notes = st.text_area("Notes (optional)") + submitted = st.form_submit_button("Add Entry") + if submitted: + entry = { + "activity_type": activity, + "duration_minutes": duration, + "tcl_score": tcl, + "notes": notes, + "timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + } + st.session_state.manual_entries.append(entry) + save_manual_entries(selected_faculty, st.session_state.manual_entries) + st.success("Entry added and saved!") + + if st.session_state.manual_entries: + manual_df = pd.DataFrame(st.session_state.manual_entries) + st.write("Your Manual Entries:") + st.dataframe(manual_df) + +# --------------------------------------- +# 🔬 TAB 8: DATA SCIENCE & MACHINE LEARNING ANALYSIS +# --------------------------------------- +with tab8: + st.subheader("🔬 Data Science & Machine Learning Analysis") + st.write("Analyze your activity data using clustering and regression.") + + # Combine simulated and manual data for analysis + combined_df = pd.concat([df, pd.DataFrame(st.session_state.manual_entries)], ignore_index=True, sort=False) + combined_df = combined_df.dropna(subset=['activity_type', 'duration_minutes', 'tcl_score']) + + # Clustering: Group activities by TCL and duration + from sklearn.cluster import KMeans + X = combined_df[['duration_minutes', 'tcl_score']] + if len(X) >= 3: + kmeans = KMeans(n_clusters=3, random_state=42) + combined_df['cluster'] = kmeans.fit_predict(X) + st.write("Activity Clusters (based on duration & TCL):") + st.dataframe(combined_df[['activity_type', 'duration_minutes', 'tcl_score', 'cluster']]) + fig_cluster = px.scatter(combined_df, x='duration_minutes', y='tcl_score', color='cluster', hover_data=['activity_type']) + st.plotly_chart(fig_cluster, use_container_width=True) + else: + st.info("Add more manual entries for clustering analysis.") + + # Regression: Predict TCL from duration (manual regression line, no statsmodels needed) + from sklearn.linear_model import LinearRegression + if len(X) >= 3: + reg = LinearRegression() + reg.fit(X[['duration_minutes']], X['tcl_score']) + combined_df['predicted_tcl'] = reg.predict(X[['duration_minutes']]) + st.write("Regression: Predict TCL from Duration") + st.dataframe(combined_df[['duration_minutes', 'tcl_score', 'predicted_tcl']]) + + scatter = go.Scatter( + x=combined_df['duration_minutes'], + y=combined_df['tcl_score'], + mode='markers', + name='Actual TCL' + ) + line = go.Scatter( + x=combined_df['duration_minutes'], + y=combined_df['predicted_tcl'], + mode='lines', + name='Regression Line' + ) + fig_reg = go.Figure([scatter, line]) + fig_reg.update_layout(title="TCL vs Duration Regression", + xaxis_title="Duration (minutes)", + yaxis_title="TCL Score") + st.plotly_chart(fig_reg, use_container_width=True) + else: + st.info("Add more manual entries for regression analysis.") + +st.markdown("---") +st.caption("© 2025 Advanced Faculty Effectiveness Dashboard | Built with ❤️ Streamlit + Plotly") \ No newline at end of file From 83070d898eabad8f45eeade03a2cd673ecdc83f9 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Oct 2025 08:50:40 +0530 Subject: [PATCH 2/2] Added a workload analyzer which can help teacher to analyze the worklods on them. --- .../MiniProjects/WorkloadAnalyzer/app.py | 530 ++++++++++++++++++ 1 file changed, 530 insertions(+) create mode 100644 Domains/Frontend/MiniProjects/WorkloadAnalyzer/app.py diff --git a/Domains/Frontend/MiniProjects/WorkloadAnalyzer/app.py b/Domains/Frontend/MiniProjects/WorkloadAnalyzer/app.py new file mode 100644 index 00000000..16021266 --- /dev/null +++ b/Domains/Frontend/MiniProjects/WorkloadAnalyzer/app.py @@ -0,0 +1,530 @@ +import streamlit as st +import pandas as pd +import numpy as np +import plotly.express as px +import plotly.graph_objects as go +import datetime +import os + +# Add these imports for PDF export +import io +try: + import pdfkit +except ImportError: + pdfkit = None + +# Optional: Uncomment if you want to use OpenAI for dynamic chat responses +# import openai + +# --------------------------------------- +# 🌐 PAGE CONFIG +# --------------------------------------- +st.set_page_config( + page_title="Faculty Effectiveness Analyzer", + page_icon="📊", + layout="wide", + initial_sidebar_state="collapsed" +) + +# --------------------------------------- +# 👩‍🏫 FACULTY DATA (with manual add section) +# --------------------------------------- +def save_faculty_profiles(profiles): + pd.DataFrame(profiles).to_json("faculty_profiles.json") + +def load_faculty_profiles(): + if os.path.exists("faculty_profiles.json"): + return pd.read_json("faculty_profiles.json", typ='dict') + else: + return None + +profiles_from_file = load_faculty_profiles() +if profiles_from_file: + faculty_profiles = profiles_from_file +else: + faculty_profiles = { + "Dr. John Doe": { + "image": "https://cdn-icons-png.flaticon.com/512/3135/3135715.png", + "rating": "4.8 / 5", + "experience": "12 Years", + "designation": "Associate Professor", + "department": "Computer Engineering", + "institution": "ABC Institute of Technology", + "about": "Passionate about building real-world technical skills and improving student outcomes through interactive learning.", + "expertise": ["Machine Learning", "HCI", "Operating Systems"], + "email": "johndoe@abc.edu", + "id": "CSE-1023", + "achievements": [ + "Best Teacher Award 2022", + "Published 10+ research papers", + "Invited Speaker at MLConf 2024" + ] + }, + "Prof. Meera Sharma": { + "image": "https://cdn-icons-png.flaticon.com/512/4140/4140048.png", + "rating": "4.5 / 5", + "experience": "8 Years", + "designation": "Assistant Professor", + "department": "Information Technology", + "institution": "XYZ College of Engineering", + "about": "Focused on student engagement and improving conceptual understanding.", + "expertise": ["Cloud Computing", "IoT", "Networking"], + "email": "meerasharma@xyz.edu", + "id": "IT-1122", + "achievements": [ + "Young Researcher Award 2021", + "Organized IoT Symposium 2023" + ] + }, + "Dr. A. Sharma": { + "image": "https://cdn-icons-png.flaticon.com/512/4140/4140037.png", + "rating": "4.9 / 5", + "experience": "15 Years", + "designation": "Professor", + "department": "AI & Data Science", + "institution": "Global Tech University", + "about": "Known for delivering complex topics with clarity and adaptive teaching methods.", + "expertise": ["AI", "Data Science", "Deep Learning"], + "email": "asharma@gtu.edu", + "id": "AIDS-1007", + "achievements": [ + "AI Excellence Award 2023", + "Published 20+ journal articles" + ] + } + } + +# --------------------------------------- +# SIDEBAR: Manual Faculty Add Section +# --------------------------------------- +st.sidebar.markdown("### ➕ Add New Faculty Profile") +with st.sidebar.form("add_faculty_form"): + new_name = st.text_input("Full Name") + new_email = st.text_input("Email") + new_id = st.text_input("Faculty ID") + new_designation = st.text_input("Designation") + new_department = st.text_input("Department") + new_institution = st.text_input("Institution") + new_experience = st.text_input("Experience (e.g. 5 Years)") + new_rating = st.text_input("Rating (e.g. 4.5 / 5)") + new_about = st.text_area("About") + new_expertise = st.text_input("Expertise (comma separated)") + new_image = st.text_input("Image URL (optional)", value="https://cdn-icons-png.flaticon.com/512/3135/3135715.png") + new_achievements = st.text_area("Achievements (one per line)") + add_faculty_btn = st.form_submit_button("Add Faculty") + + if add_faculty_btn and new_name: + faculty_profiles[new_name] = { + "image": new_image, + "rating": new_rating, + "experience": new_experience, + "designation": new_designation, + "department": new_department, + "institution": new_institution, + "about": new_about, + "expertise": [e.strip() for e in new_expertise.split(",") if e.strip()], + "email": new_email, + "id": new_id, + "achievements": [a.strip() for a in new_achievements.split("\n") if a.strip()] + } + save_faculty_profiles(faculty_profiles) + st.sidebar.success(f"Faculty '{new_name}' added! Please refresh to see in the list.") + +selected_faculty = st.sidebar.selectbox("👩‍🏫 Select Faculty", list(faculty_profiles.keys())) +faculty = faculty_profiles[selected_faculty] + +# --------------------------------------- +# 🧠 SIMULATED DATA GENERATION (PER FACULTY) +# --------------------------------------- +def generate_day(seed): + np.random.seed(seed) + activities = ['Instruction', 'Research', 'Admin', 'Email', 'Prep', 'Meeting', 'Break', 'Mentoring'] + hours = np.random.choice(range(9, 18), 10) + return pd.DataFrame({ + 'timestamp': [f"{h:02d}:00:00" for h in hours], + 'activity_type': np.random.choice(activities, 10), + 'duration_minutes': np.random.randint(15, 120, 10), + 'tcl_score': np.random.randint(10, 100, 10), + 'context_switch_flag': np.random.choice([0, 1], 10) + }) + +base_date = datetime.date(2025, 10, 13) +faculty_data = {f: {base_date - datetime.timedelta(days=i): generate_day(i+idx*10) for i in range(30)} + for idx, f in enumerate(faculty_profiles.keys())} + +# --------------------------------------- +# 📄 FACULTY PROFILE (Sliding Panel) +# --------------------------------------- +with st.expander(f"👨‍🏫 Faculty Profile: {selected_faculty}", expanded=True): + colA, colB = st.columns([1, 2]) + with colA: + st.image(faculty['image'], width=140) + st.metric("⭐ Rating", faculty['rating']) + st.metric("🏫 Experience", faculty['experience']) + with colB: + st.write(f"**Designation:** {faculty['designation']}") + st.write(f"**Department:** {faculty['department']}") + st.write(f"**Institution:** {faculty['institution']}") + st.write(f"**Email:** {faculty['email']} | **Faculty ID:** {faculty['id']}") + st.write(f"**Expertise:** {', '.join(faculty['expertise'])}") + st.write(f"📝 {faculty['about']}") + # Achievements Section + if "achievements" in faculty: + st.markdown("**🏆 Achievements:**") + for ach in faculty["achievements"]: + st.markdown(f"- {ach}") + +# --------------------------------------- +# 🗓 PERIOD SELECTION +# --------------------------------------- +st.title("📊 Advanced Faculty Effectiveness & Workload Analytics Dashboard") +period = st.radio("Select Analysis Period:", ["Daily", "Weekly", "Monthly"], horizontal=True) + +if period == "Daily": + selected_date = st.date_input("Select Date", base_date) + df = faculty_data[selected_faculty].get(selected_date, pd.DataFrame()) +elif period == "Weekly": + dates = sorted(faculty_data[selected_faculty].keys())[:7] + df = pd.concat([faculty_data[selected_faculty][d] for d in dates], keys=dates).reset_index(level=1, drop=True).rename_axis('date').reset_index() +else: + dates = sorted(faculty_data[selected_faculty].keys()) + df = pd.concat([faculty_data[selected_faculty][d] for d in dates], keys=dates).reset_index(level=1, drop=True).rename_axis('date').reset_index() + +if df.empty: + st.warning("No data found.") + st.stop() + +# --------------------------------------- +# 🧮 METRICS COMPUTATION +# --------------------------------------- +df['hour'] = pd.to_datetime(df['timestamp']).dt.hour +time_allocation = df.groupby('activity_type')['duration_minutes'].sum() +wasted_time = df['context_switch_flag'].sum() * 5 +high_load_time = df[df['tcl_score'] > 70]['duration_minutes'].sum() +avg_tcl = df['tcl_score'].mean() +peak_hour = df.groupby('hour')['tcl_score'].mean().idxmax() + +# Work-Life Balance Indicator +break_time = df[df['activity_type'] == 'Break']['duration_minutes'].sum() +work_time = df['duration_minutes'].sum() +balance_score = (break_time / work_time) * 100 if work_time else 0 + +# --------------------------------------- +# Utility: Save manual entries to CSV for persistent storage +# --------------------------------------- +def save_manual_entries(faculty_name, manual_entries): + df_manual = pd.DataFrame(manual_entries) + filename = f"{faculty_name.replace(' ', '_')}_manual_entries.csv" + df_manual.to_csv(filename, index=False) + return filename + +def load_manual_entries(faculty_name): + filename = f"{faculty_name.replace(' ', '_')}_manual_entries.csv" + try: + return pd.read_csv(filename).to_dict('records') + except Exception: + return [] + +# --------------------------------------- +# ⏱ GAUGE CHART FOR TCL +# --------------------------------------- +fig_gauge = go.Figure(go.Indicator( + mode="gauge+number", + value=avg_tcl, + title={'text': "Real-Time TCL"}, + gauge={'axis': {'range': [0, 100]}, + 'bar': {'color': "red" if avg_tcl > 70 else "green"}, + 'steps': [ + {'range': [0, 50], 'color': "lightgreen"}, + {'range': [50, 80], 'color': "orange"}, + {'range': [80, 100], 'color': "red"}]} +)) +st.plotly_chart(fig_gauge, use_container_width=True) + +# --------------------------------------- +# 🧭 KEY INDICATORS +# --------------------------------------- +k1, k2, k3, k4, k5 = st.columns(5) +k1.metric("🧠 Average TCL", f"{avg_tcl:.1f}/100") +k2.metric("⏳ Context Switch Time Wasted", f"{wasted_time} min") +k3.metric("🔥 High Load Duration", f"{high_load_time} min") +k4.metric("🕒 Peak Load Hour", f"{peak_hour}:00") +k5.metric("⚖️ Work-Life Balance", f"{balance_score:.1f}%") + +st.markdown("---") + +# --------------------------------------- +# 📊 TABS STRUCTURE +# --------------------------------------- +tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8 = st.tabs([ + "📌 Activity Overview", + "📈 Trends & Graphs", + "🤖 AI Insights", + "📊 Advanced Analytics", + "📥 Reports", + "🧑‍💻 Virtual Assistant", + "✍️ Manual Entry", + "🔬 Data Science & ML" +]) + +# --------------------------------------- +# 📌 TAB 1: ACTIVITY OVERVIEW +# --------------------------------------- +with tab1: + col1, col2 = st.columns(2) + with col1: + fig = px.pie(values=time_allocation.values, names=time_allocation.index, + hole=0.4, color_discrete_sequence=px.colors.sequential.Viridis, + title="🕒 Time Allocation by Activity") + fig.update_traces(textinfo='percent+label') + st.plotly_chart(fig, use_container_width=True) + + with col2: + df_treemap = df.groupby('activity_type')['tcl_score'].mean().reset_index() + fig_tree = px.treemap(df_treemap, path=['activity_type'], values='tcl_score', + color='tcl_score', color_continuous_scale='Blues', + title="🌳 Activity Cognitive Load Tree") + st.plotly_chart(fig_tree, use_container_width=True) + +# --------------------------------------- +# 📈 TAB 2: TRENDS & GRAPHS +# --------------------------------------- +with tab2: + if period == "Daily": + hourly_avg = df.groupby('hour')['tcl_score'].mean().reset_index() + st.subheader("📅 Hourly Cognitive Load Trend") + st.plotly_chart(px.line(hourly_avg, x='hour', y='tcl_score', markers=True, title="Hourly TCL Curve"), use_container_width=True) + else: + st.subheader(f"📆 {period} Trends") + trend_tcl = df.groupby('date')['tcl_score'].mean().reset_index() + trend_time = df.groupby('date')['duration_minutes'].sum().reset_index() + c1, c2 = st.columns(2) + with c1: + st.plotly_chart(px.line(trend_tcl, x='date', y='tcl_score', title="📈 Avg TCL over time", markers=True), use_container_width=True) + with c2: + st.plotly_chart(px.bar(trend_time, x='date', y='duration_minutes', title="⏳ Total Workload per Day"), use_container_width=True) + +# --------------------------------------- +# 🧠 TAB 3: AI INSIGHTS +# --------------------------------------- +with tab3: + st.subheader("🤖 AI-Powered Efficiency Insights") + insights = [] + if wasted_time > 30: + insights.append(f"⚠️ High context switching detected: {wasted_time} minutes wasted. Batch administrative work at the end of the day.") + if high_load_time > 120: + insights.append("🔥 High cognitive load period exceeded 2 hours. Introduce structured breaks.") + if avg_tcl < 40: + insights.append("📉 TCL below expected average. Increase interactive sessions.") + if avg_tcl > 80: + insights.append("🧠 Exceptional focus periods detected. Schedule complex lectures during these hours.") + if balance_score < 5: + insights.append("⚖️ Work-life balance is low. Encourage more breaks.") + if not insights: + st.success("🎉 Excellent balance detected. No major issues found.") + else: + for ins in insights: + st.info(ins) + +# --------------------------------------- +# 📊 TAB 4: ADVANCED ANALYTICS +# --------------------------------------- +with tab4: + st.subheader("📊 Activity vs Cognitive Load Scatter Analysis") + fig_scatter = px.scatter( + df, x='duration_minutes', y='tcl_score', color='activity_type', + size='duration_minutes', hover_data=['timestamp'], + title="⏳ Duration vs 🧠 TCL Score Scatter" + ) + st.plotly_chart(fig_scatter, use_container_width=True) + + st.subheader("🔸 Load Distribution Heatmap") + df_heat = df.pivot_table(index='activity_type', columns='hour', values='tcl_score', aggfunc='mean') + fig_heat = go.Figure(data=go.Heatmap(z=df_heat.values, x=df_heat.columns, y=df_heat.index, colorscale='Reds')) + fig_heat.update_layout(title="Heatmap of Cognitive Load by Hour & Activity", xaxis_nticks=12) + st.plotly_chart(fig_heat, use_container_width=True) + +# --------------------------------------- +# 📥 TAB 5: REPORTS +# --------------------------------------- +with tab5: + st.subheader("📤 Generate & Download Report") + st.dataframe(df) + total_duration = df['duration_minutes'].sum() / 60 + st.markdown(f"🕒 **Total Hours Worked:** {total_duration:.2f} hrs") + st.markdown(f"📌 **Distinct Activities:** {df['activity_type'].nunique()}") + st.download_button( + label="📥 Download CSV Report", + data=df.to_csv(index=False).encode('utf-8'), + file_name=f"{selected_faculty}_{period.lower()}_report.csv", + mime='text/csv' + ) + # PDF Export Option + if pdfkit: + html = df.to_html(index=False) + pdf_bytes = pdfkit.from_string(html, False) + st.download_button( + label="📄 Download PDF Report", + data=pdf_bytes, + file_name=f"{selected_faculty}_{period.lower()}_report.pdf", + mime='application/pdf' + ) + else: + st.info("PDF export requires `pdfkit` and `wkhtmltopdf` installed. Run `pip install pdfkit` and download wkhtmltopdf from https://wkhtmltopdf.org/downloads.html") + +# --------------------------------------- +# 🧑‍💻 TAB 6: VIRTUAL ASSISTANT (Dynamic Chat) +# --------------------------------------- +with tab6: + st.markdown("## 💬 Faculty Virtual Assistant") + st.write("Ask about your schedule, workload, breaks, or cognitive load. Example: *How busy am I today?*") + + if "chat_history" not in st.session_state: + st.session_state.chat_history = [] + + user_query = st.chat_input("Type your question here...") + + def get_dynamic_response(query): + context = ( + f"Faculty: {selected_faculty}\n" + f"Total work time: {work_time:.1f} minutes\n" + f"Break time: {break_time:.1f} minutes\n" + f"Work-life balance score: {balance_score:.1f}%\n" + f"Average TCL: {avg_tcl:.1f}/100\n" + f"High load duration: {high_load_time} minutes\n" + f"Context switch time wasted: {wasted_time} minutes\n" + f"Peak busy hour: {peak_hour}:00\n" + f"Distinct activities: {df['activity_type'].nunique()}\n" + ) + prompt = ( + f"You are a helpful assistant for faculty workload analytics. " + f"Here is the faculty's current dashboard data:\n{context}\n" + f"User question: {query}\n" + f"Answer in a friendly, concise way using the data above." + ) + # Uncomment below to use OpenAI + # try: + # response = openai.ChatCompletion.create( + # model="gpt-3.5-turbo", + # messages=[ + # {"role": "system", "content": "You are a helpful assistant for faculty workload analytics."}, + # {"role": "user", "content": prompt} + # ], + # max_tokens=150 + # ) + # return response.choices[0].message.content.strip() + # except Exception as e: + # return f"Sorry, I couldn't fetch a response. ({e})" + # --- Fallback: Static rule-based response --- + query = query.lower() + if "busy" in query or "schedule" in query: + return f"You have worked a total of {work_time:.1f} minutes today. Peak busy hour: {peak_hour}:00." + elif "break" in query or "rest" in query: + return f"You took {break_time:.1f} minutes of break today. Work-life balance score: {balance_score:.1f}%." + elif "tcl" in query or "load" in query: + return f"Your average TCL is {avg_tcl:.1f}/100. High load duration: {high_load_time} minutes." + elif "context switch" in query or "distraction" in query: + return f"Context switching wasted {wasted_time} minutes today. Try batching similar tasks." + elif "activities" in query: + return f"Distinct activities performed: {df['activity_type'].nunique()}." + elif "report" in query or "download" in query: + return "You can download your report from the 'Reports' tab." + else: + return "I'm here to help! Ask about your workload, schedule, breaks, or cognitive load." + + if user_query: + st.session_state.chat_history.append(("user", user_query)) + response = get_dynamic_response(user_query) + st.session_state.chat_history.append(("assistant", response)) + + for role, msg in st.session_state.chat_history: + st.chat_message(role).write(msg) + +# --------------------------------------- +# ✍️ TAB 7: MANUAL ENTRY (with persistent storage) +# --------------------------------------- +with tab7: + st.subheader("✍️ Add Your Own Experience Data") + st.write("Manually log your activities, workload, or notes for today. Entries will be saved and used for analytics.") + + if "manual_entries" not in st.session_state: + st.session_state.manual_entries = load_manual_entries(selected_faculty) + + with st.form("manual_entry_form"): + activity = st.selectbox("Activity Type", ['Instruction', 'Research', 'Admin', 'Email', 'Prep', 'Meeting', 'Break', 'Mentoring', 'Other']) + duration = st.number_input("Duration (minutes)", min_value=1, max_value=480, value=60) + tcl = st.slider("TCL Score (1-100)", min_value=1, max_value=100, value=50) + notes = st.text_area("Notes (optional)") + submitted = st.form_submit_button("Add Entry") + if submitted: + entry = { + "activity_type": activity, + "duration_minutes": duration, + "tcl_score": tcl, + "notes": notes, + "timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + } + st.session_state.manual_entries.append(entry) + save_manual_entries(selected_faculty, st.session_state.manual_entries) + st.success("Entry added and saved!") + + if st.session_state.manual_entries: + manual_df = pd.DataFrame(st.session_state.manual_entries) + st.write("Your Manual Entries:") + st.dataframe(manual_df) + +# --------------------------------------- +# 🔬 TAB 8: DATA SCIENCE & MACHINE LEARNING ANALYSIS +# --------------------------------------- +with tab8: + st.subheader("🔬 Data Science & Machine Learning Analysis") + st.write("Analyze your activity data using clustering and regression.") + + # Combine simulated and manual data for analysis + combined_df = pd.concat([df, pd.DataFrame(st.session_state.manual_entries)], ignore_index=True, sort=False) + combined_df = combined_df.dropna(subset=['activity_type', 'duration_minutes', 'tcl_score']) + + # Clustering: Group activities by TCL and duration + from sklearn.cluster import KMeans + X = combined_df[['duration_minutes', 'tcl_score']] + if len(X) >= 3: + kmeans = KMeans(n_clusters=3, random_state=42) + combined_df['cluster'] = kmeans.fit_predict(X) + st.write("Activity Clusters (based on duration & TCL):") + st.dataframe(combined_df[['activity_type', 'duration_minutes', 'tcl_score', 'cluster']]) + fig_cluster = px.scatter(combined_df, x='duration_minutes', y='tcl_score', color='cluster', hover_data=['activity_type']) + st.plotly_chart(fig_cluster, use_container_width=True) + else: + st.info("Add more manual entries for clustering analysis.") + + # Regression: Predict TCL from duration (manual regression line, no statsmodels needed) + from sklearn.linear_model import LinearRegression + if len(X) >= 3: + reg = LinearRegression() + reg.fit(X[['duration_minutes']], X['tcl_score']) + combined_df['predicted_tcl'] = reg.predict(X[['duration_minutes']]) + st.write("Regression: Predict TCL from Duration") + st.dataframe(combined_df[['duration_minutes', 'tcl_score', 'predicted_tcl']]) + + scatter = go.Scatter( + x=combined_df['duration_minutes'], + y=combined_df['tcl_score'], + mode='markers', + name='Actual TCL' + ) + line = go.Scatter( + x=combined_df['duration_minutes'], + y=combined_df['predicted_tcl'], + mode='lines', + name='Regression Line' + ) + fig_reg = go.Figure([scatter, line]) + fig_reg.update_layout(title="TCL vs Duration Regression", + xaxis_title="Duration (minutes)", + yaxis_title="TCL Score") + st.plotly_chart(fig_reg, use_container_width=True) + else: + st.info("Add more manual entries for regression analysis.") + +st.markdown("---") +st.caption("© 2025 Advanced Faculty Effectiveness Dashboard | Built with ❤️ Streamlit + Plotly") \ No newline at end of file