Heloise1234's picture
Upload 2 files
a3ed528 verified
"""
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()