Spaces:
Sleeping
Sleeping
| """ | |
| 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() | |