""" Smart Study Planner — Group H6 Hugging Face Gradio App """ import gradio as gr import pandas as pd import matplotlib.pyplot as plt import matplotlib matplotlib.use("Agg") from datetime import datetime, date import io # ── OOP CLASSES (same logic as original app) ────────────────── class User: def __init__(self, name): self.name = name class Student(User): def __init__(self, name, level): super().__init__(name) self.level = level class Task: def __init__(self, title, subject, deadline, difficulty, duration): self.title = title self.subject = subject self.deadline = deadline # datetime.date object self.difficulty = difficulty.lower() self.duration = duration self.completed = False def mark_completed(self): self.completed = True def is_overdue(self): return self.deadline < date.today() and not self.completed def get_priority(self): days_left = (self.deadline - date.today()).days if days_left <= 1: p = 3 elif days_left <= 3: p = 2 else: p = 1 if self.difficulty == "hard": p += 3 elif self.difficulty == "medium": p += 2 else: p += 1 return p class StudyPlanner: def __init__(self): self._tasks = [] def add_task(self, task): self._tasks.append(task) def get_tasks(self): return self._tasks def remove_task(self, index): if 0 <= index < len(self._tasks): self._tasks.pop(index) def mark_completed(self, index): if 0 <= index < len(self._tasks): self._tasks[index].mark_completed() def to_dataframe(self): if not self._tasks: return pd.DataFrame() rows = [] for i, t in enumerate(self._tasks): rows.append({ "#": i + 1, "Title": t.title, "Subject": t.subject, "Deadline": str(t.deadline), "Difficulty": t.difficulty.capitalize(), "Hours": t.duration, "Priority": t.get_priority(), "Status": "✅ Done" if t.completed else ("🔴 Overdue" if t.is_overdue() else "🕐 Pending"), "Urgent": "⚠️ URGENT" if t.get_priority() >= 5 and not t.completed else "", }) return pd.DataFrame(rows) def study_plan_df(self): pending = [t for t in self._tasks if not t.completed] if not pending: return pd.DataFrame() rows = [] for t in pending: rows.append({ "Title": t.title, "Subject": t.subject, "Deadline": str(t.deadline), "Difficulty": t.difficulty.capitalize(), "Hours": t.duration, "Priority Score": t.get_priority(), "Status": "🔴 OVERDUE" if t.is_overdue() else "🕐 Pending", }) df = pd.DataFrame(rows) return df.sort_values("Priority Score", ascending=False).reset_index(drop=True) def plot_by_subject(self): if not self._tasks: return None subjects = [t.subject for t in self._tasks] counts = pd.Series(subjects).value_counts() fig, ax = plt.subplots(figsize=(8, 4)) colors = plt.cm.Set3.colors[:len(counts)] counts.plot(kind="bar", ax=ax, color=colors, edgecolor="black") ax.set_title("Number of Tasks by Subject", fontsize=14, fontweight="bold") ax.set_xlabel("Subject") ax.set_ylabel("Count") ax.tick_params(axis="x", rotation=30) plt.tight_layout() return fig # ── GLOBAL STATE ────────────────────────────────────────────── planner = StudyPlanner() student = None # ── GRADIO FUNCTIONS ────────────────────────────────────────── def set_student(name, level): global student if not name.strip(): return "❌ Please enter your name.", "" student = Student(name.strip(), level) return f"👋 Welcome, **{student.name}** ({student.level})! You can now add your tasks below.", "" def add_task(title, subject, deadline_str, difficulty, duration): if not title.strip() or not subject.strip(): return "❌ Title and subject are required.", planner.to_dataframe() try: deadline = datetime.strptime(deadline_str, "%Y-%m-%d").date() except ValueError: return "❌ Invalid date. Use format YYYY-MM-DD.", planner.to_dataframe() try: dur = float(duration) except ValueError: return "❌ Duration must be a number.", planner.to_dataframe() task = Task(title.strip(), subject.strip(), deadline, difficulty, dur) planner.add_task(task) p = task.get_priority() alert = " ⚠️ **URGENT task!**" if p >= 5 else "" return f"✅ Task **'{title}'** added! Priority score: **{p}**.{alert}", planner.to_dataframe() def view_tasks(): df = planner.to_dataframe() if df.empty: return "No tasks yet. Add your first task above!", df urgent_count = sum(1 for t in planner.get_tasks() if t.get_priority() >= 5 and not t.completed) msg = f"📋 **{len(planner.get_tasks())} task(s)** total." if urgent_count: msg += f" ⚠️ **{urgent_count} urgent task(s)!**" return msg, df def generate_plan(): df = planner.study_plan_df() if df.empty: return "🎉 No pending tasks — you're all caught up!", df urgent = df[df["Priority Score"] >= 5] msg = f"📅 Study plan generated — **{len(df)} pending task(s)**, sorted by priority." if not urgent.empty: msg += f" ⚠️ **{len(urgent)} URGENT** (score ≥ 5)!" return msg, df def mark_done(task_num_str): try: idx = int(task_num_str) - 1 planner.mark_completed(idx) return f"✅ Task #{int(task_num_str)} marked as completed!", planner.to_dataframe() except (ValueError, IndexError): return "❌ Invalid task number.", planner.to_dataframe() def remove_task(task_num_str): try: idx = int(task_num_str) - 1 planner.remove_task(idx) return f"🗑️ Task #{int(task_num_str)} removed.", planner.to_dataframe() except (ValueError, IndexError): return "❌ Invalid task number.", planner.to_dataframe() def show_chart(): fig = planner.plot_by_subject() if fig is None: return None return fig # ── UI ──────────────────────────────────────────────────────── with gr.Blocks(theme=gr.themes.Soft(), title="Smart Study Planner") as demo: gr.Markdown(""" # 📚 Smart Study Planner **Group H6 — ESCP Business School** Manage your tasks, track priorities, and never miss a deadline. """) # ── SECTION 1: Student Setup with gr.Accordion("👤 Step 1 — Enter your details", open=True): with gr.Row(): name_input = gr.Textbox(label="Your Name", placeholder="e.g. Julia") level_input = gr.Dropdown( choices=["Bachelor", "Master", "MBA", "PhD", "Other"], value="Master", label="Study Level" ) welcome_btn = gr.Button("Start Planning →", variant="primary") welcome_msg = gr.Markdown("") welcome_btn.click(set_student, inputs=[name_input, level_input], outputs=[welcome_msg, gr.Textbox(visible=False)]) # ── SECTION 2: Add Task with gr.Accordion("➕ Step 2 — Add a Task", open=True): with gr.Row(): t_title = gr.Textbox(label="Task Title", placeholder="e.g. Chapter 5 Revision") t_subject = gr.Textbox(label="Subject", placeholder="e.g. Mathematics") with gr.Row(): t_deadline = gr.Textbox(label="Deadline (YYYY-MM-DD)", placeholder=f"{date.today().strftime('%Y-%m-%d')}") t_difficulty = gr.Dropdown(choices=["Easy", "Medium", "Hard"], value="Medium", label="Difficulty") t_duration = gr.Number(label="Duration (hours)", value=2, minimum=0.5, maximum=20) add_btn = gr.Button("Add Task", variant="primary") add_msg = gr.Markdown("") task_table = gr.DataFrame(label="Your Tasks", wrap=True) add_btn.click(add_task, inputs=[t_title, t_subject, t_deadline, t_difficulty, t_duration], outputs=[add_msg, task_table]) # ── SECTION 3: View / Plan / Actions with gr.Accordion("📋 Step 3 — View & Manage Tasks", open=False): with gr.Row(): view_btn = gr.Button("🔍 View All Tasks") plan_btn = gr.Button("📅 Generate Study Plan", variant="primary") action_msg = gr.Markdown("") plan_table = gr.DataFrame(label="Study Plan / Task List", wrap=True) view_btn.click(view_tasks, outputs=[action_msg, plan_table]) plan_btn.click(generate_plan, outputs=[action_msg, plan_table]) gr.Markdown("---") with gr.Row(): task_num_done = gr.Textbox(label="Task # to mark done", placeholder="e.g. 2") done_btn = gr.Button("✅ Mark as Completed") task_num_remove = gr.Textbox(label="Task # to remove", placeholder="e.g. 3") remove_btn = gr.Button("🗑️ Remove Task", variant="stop") done_msg = gr.Markdown("") done_table = gr.DataFrame(wrap=True) done_btn.click(mark_done, inputs=[task_num_done], outputs=[done_msg, done_table]) remove_btn.click(remove_task, inputs=[task_num_remove], outputs=[done_msg, done_table]) # ── SECTION 4: Chart with gr.Accordion("📊 Step 4 — Visualise Tasks by Subject", open=False): chart_btn = gr.Button("📊 Show Chart") chart_output = gr.Plot() chart_btn.click(show_chart, outputs=[chart_output]) gr.Markdown(""" --- **Priority Score Guide:** | Score | Meaning | |-------|---------| | 2 | Low priority — Easy + far deadline | | 4 | Medium priority | | 5–6 | ⚠️ URGENT — Act now! | *Built with Python + Gradio · Group H6 ESCP* """) demo.launch()