Files

141 lines
4.8 KiB
Python

"""Prioritization Engine — generates actionable suggestions based on task state."""
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from sqlalchemy.orm import Session
from app.models import Task
BERLIN_TZ = ZoneInfo("Europe/Berlin")
def generate_suggestions(db: Session) -> list[dict]:
"""Analyze open tasks and generate prioritization suggestions.
Returns a list of suggestion dicts with: id, content, type, severity.
"""
now = datetime.now(BERLIN_TZ)
today = now.date()
suggestions = []
suggestion_id = 1
open_tasks = db.query(Task).filter(Task.status == "open").all()
if not open_tasks:
return []
# --- 1. Overdue tasks ---
overdue_tasks = [
t for t in open_tasks
if t.due_date and t.due_date.date() < today
]
for t in overdue_tasks[:3]: # Limit to top 3
days_overdue = (today - t.due_date.date()).days
suggestions.append({
"id": suggestion_id,
"content": f"⚠️ \"{t.title}\" is {days_overdue} day{'s' if days_overdue != 1 else ''} overdue. Reschedule or complete it.",
"type": "overdue",
"severity": "high",
"task_id": t.id,
})
suggestion_id += 1
# --- 2. Due tomorrow ---
tomorrow = today + timedelta(days=1)
due_tomorrow = [
t for t in open_tasks
if t.due_date and t.due_date.date() == tomorrow
]
for t in due_tomorrow:
suggestions.append({
"id": suggestion_id,
"content": f"📅 \"{t.title}\" is due tomorrow.",
"type": "upcoming",
"severity": "medium",
"task_id": t.id,
})
suggestion_id += 1
# --- 3. Due this week ---
week_end = today + timedelta(days=7)
due_this_week = [
t for t in open_tasks
if t.due_date and today < t.due_date.date() <= week_end
and t.due_date.date() != tomorrow # Already covered above
]
if len(due_this_week) > 3:
suggestions.append({
"id": suggestion_id,
"content": f"📋 You have {len(due_this_week)} tasks due this week. Plan your time.",
"type": "workload",
"severity": "medium",
})
suggestion_id += 1
# --- 4. High-priority tasks without due dates ---
high_no_date = [
t for t in open_tasks
if t.priority and t.priority <= 2 and not t.due_date
]
for t in high_no_date[:2]: # Limit to top 2
suggestions.append({
"id": suggestion_id,
"content": f"🎯 \"{t.title}\" is high priority but has no deadline. Set a due date.",
"type": "missing_date",
"severity": "medium",
"task_id": t.id,
})
suggestion_id += 1
# --- 5. Tasks idle for 7+ days ---
idle_threshold = now - timedelta(days=7)
idle_tasks = [
t for t in open_tasks
if t.created_at and t.created_at < idle_threshold
and (not t.due_date) # Only flag idle tasks without deadlines
and t.priority and t.priority >= 3 # Low/medium priority
]
if len(idle_tasks) > 5:
suggestions.append({
"id": suggestion_id,
"content": f"🧹 {len(idle_tasks)} low-priority tasks have been sitting for over a week. Review and clean up.",
"type": "stale",
"severity": "low",
})
suggestion_id += 1
elif idle_tasks:
oldest = max(idle_tasks, key=lambda t: (now - t.created_at).days if t.created_at else 0)
if oldest.created_at:
days_idle = (now - oldest.created_at).days
suggestions.append({
"id": suggestion_id,
"content": f"🧹 \"{oldest.title}\" has been open for {days_idle} days. Still relevant?",
"type": "stale",
"severity": "low",
"task_id": oldest.id,
})
suggestion_id += 1
# --- 6. Too many high-priority tasks ---
high_priority_count = len([t for t in open_tasks if t.priority and t.priority <= 2])
if high_priority_count > 5:
suggestions.append({
"id": suggestion_id,
"content": f"🔥 You have {high_priority_count} high-priority tasks. If everything is urgent, nothing is. Consider demoting some.",
"type": "overload",
"severity": "medium",
})
suggestion_id += 1
# --- 7. No tasks due soon (might need planning) ---
tasks_with_dates = [t for t in open_tasks if t.due_date]
if len(open_tasks) > 10 and len(tasks_with_dates) < 3:
suggestions.append({
"id": suggestion_id,
"content": "📆 Most of your tasks have no due dates. Consider scheduling your top priorities.",
"type": "planning",
"severity": "low",
})
suggestion_id += 1
return suggestions