Skip to content

Commit fcc2259

Browse files
committedMar 20, 2025
Add task management functionality with JSON storage and API endpoints
1 parent 23be965 commit fcc2259

File tree

5 files changed

+247
-277
lines changed

5 files changed

+247
-277
lines changed
 

‎backend/api/endpoints/smart.py

+46-72
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from backend.core.ai import categorize_email, schedule_meeting, prioritize_task
88
from backend.integrations.gmail_service import GmailService
99
from backend.integrations.calendar_service import CalendarService
10-
from backend.integrations.trello_service import TrelloService
10+
from backend.api.endpoints.task import get_tasks, save_tasks
1111

1212
router = APIRouter(prefix="/api/smart", tags=["smart"])
1313

@@ -17,15 +17,11 @@ def get_gmail_service():
1717
def get_calendar_service():
1818
return CalendarService()
1919

20-
def get_trello_service():
21-
return TrelloService()
22-
2320
@router.post("/email-process")
2421
def process_email_with_ai(
2522
request: EmailRequest,
2623
gmail_service: GmailService = Depends(get_gmail_service),
27-
calendar_service: CalendarService = Depends(get_calendar_service),
28-
trello_service: TrelloService = Depends(get_trello_service)
24+
calendar_service: CalendarService = Depends(get_calendar_service)
2925
):
3026
"""Process an email with AI, categorize it, and take appropriate actions."""
3127
try:
@@ -63,19 +59,26 @@ def process_email_with_ai(
6359

6460
# Check for task-related emails
6561
if "task" in ai_analysis.lower() or "todo" in ai_analysis.lower() or "action" in ai_analysis.lower():
66-
# Get the first Trello board and list for demo purposes
67-
boards = trello_service.get_boards()
68-
if boards:
69-
lists = trello_service.get_lists(boards[0]['id'])
70-
if lists:
71-
# Create a task in Trello
72-
card = trello_service.create_card(
73-
list_id=lists[0]['id'],
74-
name=f"Task from email: {subject}",
75-
description=f"Generated from email:\n\n{request.email_text[:1000]}...",
76-
due=None # Could extract deadline from email text with more complex regex
77-
)
78-
actions_taken.append({"type": "task_created", "details": card})
62+
# Create a task from the email
63+
task = {
64+
"id": f"task_{int(datetime.now().timestamp())}",
65+
"description": f"Task from email: {subject}",
66+
"assigned_to": "Auto-assigned",
67+
"deadline": (datetime.now() + timedelta(days=7)).isoformat(),
68+
"priority": "Medium",
69+
"status": "To Do",
70+
"analysis": ai_analysis,
71+
"created_at": datetime.now().isoformat(),
72+
"source": "email",
73+
"email_content": request.email_text[:1000]
74+
}
75+
76+
# Save to local storage
77+
tasks = get_tasks()
78+
tasks.append(task)
79+
save_tasks(tasks)
80+
81+
actions_taken.append({"type": "task_created", "details": task})
7982

8083
# Reply to the email with a confirmation of actions taken
8184
if actions_taken:
@@ -156,11 +159,9 @@ def smart_schedule_meeting(
156159

157160
@router.post("/create-task")
158161
def smart_create_task(
159-
request: TaskRequest,
160-
board_name: Optional[str] = "Tasks",
161-
trello_service: TrelloService = Depends(get_trello_service)
162+
request: TaskRequest
162163
):
163-
"""Analyze a task with AI and create it in Trello with appropriate labels and priority."""
164+
"""Analyze a task with AI and create it with appropriate tags based on priority."""
164165
try:
165166
# 1. Get AI analysis
166167
ai_analysis = prioritize_task(request)
@@ -183,62 +184,35 @@ def smart_create_task(
183184
elif days_until_deadline <= 7:
184185
tags.append("Due This Week")
185186

186-
# 3. Determine which list to place the task in
187-
list_name = "To Do"
187+
# 3. Determine status based on analysis
188+
status = "To Do"
188189
if "started" in ai_analysis.lower() or "in progress" in ai_analysis.lower():
189-
list_name = "In Progress"
190-
191-
# 4. Find or create the board and list
192-
boards = trello_service.get_boards()
193-
board_id = None
190+
status = "In Progress"
191+
192+
# 4. Create task
193+
task = {
194+
"id": f"task_{int(datetime.now().timestamp())}",
195+
"description": request.description,
196+
"assigned_to": request.assigned_to,
197+
"deadline": request.deadline,
198+
"priority": request.priority,
199+
"status": status,
200+
"tags": tags,
201+
"analysis": ai_analysis,
202+
"created_at": datetime.now().isoformat()
203+
}
194204

195-
# Look for an existing board with the specified name
196-
for board in boards:
197-
if board['name'].lower() == board_name.lower():
198-
board_id = board['id']
199-
break
200-
201-
# Create a new board if needed
202-
if not board_id:
203-
new_board = trello_service.create_board(board_name)
204-
board_id = new_board['id']
205-
206-
# Get lists for this board
207-
lists = trello_service.get_lists(board_id)
208-
list_id = None
209-
210-
# Find the appropriate list
211-
for lst in lists:
212-
if lst['name'].lower() == list_name.lower():
213-
list_id = lst['id']
214-
break
215-
216-
# Create the list if it doesn't exist
217-
if not list_id and lists:
218-
new_list = trello_service.create_list(board_id, list_name)
219-
list_id = new_list['id']
220-
elif not list_id and not lists:
221-
# Create default lists if board is empty
222-
to_do_list = trello_service.create_list(board_id, "To Do")
223-
in_progress_list = trello_service.create_list(board_id, "In Progress")
224-
done_list = trello_service.create_list(board_id, "Done")
225-
list_id = to_do_list['id']
226-
227-
# 5. Create the card with all the collected information
228-
card = trello_service.create_card(
229-
list_id=list_id,
230-
name=request.description,
231-
description=f"Assigned to: {request.assigned_to}\nAI Analysis: {ai_analysis}",
232-
due=deadline_date.isoformat(),
233-
labels=tags
234-
)
205+
# 5. Save to local storage
206+
tasks = get_tasks()
207+
tasks.append(task)
208+
save_tasks(tasks)
235209

236210
return {
237211
"analysis": ai_analysis,
238212
"task_created": True,
239-
"task_details": card,
213+
"task_details": task,
240214
"tags": tags,
241-
"list": list_name
215+
"status": status
242216
}
243217

244218
except Exception as e:

‎backend/api/endpoints/task.py

+70-26
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,33 @@
1-
from fastapi import APIRouter, HTTPException, Depends
1+
from fastapi import APIRouter, HTTPException, Depends, Body
22
from typing import List, Optional
3-
from backend.core.models import TaskRequest
3+
from backend.core.models import TaskRequest, TaskStatus
44
from backend.core.ai import prioritize_task
5-
from backend.integrations.trello_service import TrelloService
6-
5+
import json
6+
import os
7+
from datetime import datetime
8+
from pathlib import Path
9+
from pydantic import BaseModel, Field, EmailStr, field_validator
710
router = APIRouter(prefix="/api", tags=["task"])
811

9-
def get_trello_service():
10-
return TrelloService()
12+
# Create a simple file-based task storage
13+
TASKS_FILE = Path("backend/data/tasks.json")
14+
15+
def get_tasks():
16+
"""Get all tasks from the local storage."""
17+
if not TASKS_FILE.exists():
18+
TASKS_FILE.parent.mkdir(parents=True, exist_ok=True)
19+
return []
20+
21+
try:
22+
with open(TASKS_FILE, "r") as f:
23+
return json.load(f)
24+
except (json.JSONDecodeError, FileNotFoundError):
25+
return []
26+
27+
def save_tasks(tasks):
28+
"""Save tasks to the local storage."""
29+
with open(TASKS_FILE, "w") as f:
30+
json.dump(tasks, f, indent=2)
1131

1232
@router.post("/prioritize-task")
1333
def api_prioritize_task(request: TaskRequest):
@@ -17,34 +37,58 @@ def api_prioritize_task(request: TaskRequest):
1737
except Exception as e:
1838
raise HTTPException(status_code=500, detail=str(e))
1939

20-
@router.get("/trello/boards")
21-
def get_trello_boards(trello_service: TrelloService = Depends(get_trello_service)):
40+
@router.get("/tasks")
41+
def get_all_tasks():
42+
"""Get all tasks."""
2243
try:
23-
boards = trello_service.get_boards()
24-
return {"boards": boards}
44+
return {"tasks": get_tasks()}
2545
except Exception as e:
2646
raise HTTPException(status_code=500, detail=str(e))
2747

28-
@router.post("/trello/board")
29-
def create_trello_board(name: str, description: Optional[str] = None, trello_service: TrelloService = Depends(get_trello_service)):
48+
@router.post("/task")
49+
def create_task(request: TaskRequest):
50+
"""Create a new task."""
3051
try:
31-
board = trello_service.create_board(name, description)
32-
return board
52+
# Use the AI to analyze the task
53+
analysis = prioritize_task(request)
54+
55+
# Create the task
56+
task = {
57+
"id": f"task_{int(datetime.now().timestamp())}",
58+
"description": request.description,
59+
"assigned_to": request.assigned_to,
60+
"deadline": request.deadline,
61+
"priority": request.priority,
62+
"status": "To Do",
63+
"analysis": analysis,
64+
"created_at": datetime.now().isoformat()
65+
}
66+
67+
# Save to local storage
68+
tasks = get_tasks()
69+
tasks.append(task)
70+
save_tasks(tasks)
71+
72+
return task
3373
except Exception as e:
3474
raise HTTPException(status_code=500, detail=str(e))
3575

36-
@router.post("/trello/card")
37-
def create_trello_card(
38-
list_id: str,
39-
name: str,
40-
description: Optional[str] = None,
41-
due: Optional[str] = None,
42-
labels: Optional[List[str]] = None,
43-
members: Optional[List[str]] = None,
44-
trello_service: TrelloService = Depends(get_trello_service)
45-
):
76+
class StatusUpdate(BaseModel):
77+
status: str
78+
79+
@router.put("/task/{task_id}/status")
80+
def update_task_status(task_id: str, update: StatusUpdate):
81+
"""Update a task's status."""
4682
try:
47-
card = trello_service.create_card(list_id, name, description, due, labels, members)
48-
return card
83+
tasks = get_tasks()
84+
85+
for task in tasks:
86+
if task.get("id") == task_id:
87+
task["status"] = update.status
88+
task["updated_at"] = datetime.now().isoformat()
89+
save_tasks(tasks)
90+
return task
91+
92+
raise HTTPException(status_code=404, detail="Task not found")
4993
except Exception as e:
5094
raise HTTPException(status_code=500, detail=str(e))

‎backend/core/models.py

+94-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,102 @@
1-
from pydantic import BaseModel
2-
from typing import List, Optional
1+
from pydantic import BaseModel, Field, EmailStr, field_validator
2+
from typing import List, Optional, Dict, Any, Union
3+
from datetime import datetime, date
4+
from enum import Enum
5+
import re
36

7+
# Enums for consistent value handling
8+
class Priority(str, Enum):
9+
LOW = "Low"
10+
MEDIUM = "Medium"
11+
HIGH = "High"
12+
URGENT = "Urgent"
13+
14+
class TaskStatus(str, Enum):
15+
TODO = "To Do"
16+
IN_PROGRESS = "In Progress"
17+
DONE = "Done"
18+
19+
# Base models
420
class EmailRequest(BaseModel):
5-
email_text: str
6-
21+
"""Model for email content to be analyzed by AI."""
22+
email_text: str = Field(...,
23+
description="Full email text including headers and body.",
24+
examples=["From: john@example.com\nSubject: Meeting Request\n\nCan we schedule a meeting for next week?"])
25+
726
class MeetingRequest(BaseModel):
8-
organizer: str
9-
attendees: List[str]
10-
proposed_dates: List[str]
11-
duration: str
27+
"""Model for meeting scheduling requests."""
28+
organizer: str = Field(...,
29+
description="Name or email of the meeting organizer",
30+
examples=["John Smith", "john@example.com"])
31+
attendees: List[str] = Field(...,
32+
description="List of attendee names or emails",
33+
examples=[["jane@example.com", "Mark Wilson", "sarah@example.com"]])
34+
proposed_dates: List[str] = Field(...,
35+
description="List of potential meeting dates in YYYY-MM-DD format",
36+
examples=[["2025-04-01", "2025-04-02", "2025-04-03"]])
37+
duration: str = Field(...,
38+
description="Meeting duration in hours or minutes",
39+
examples=["1 hour", "30 minutes", "2 hours"])
1240

41+
@field_validator('proposed_dates')
42+
def validate_dates(cls, dates):
43+
"""Ensure dates are in the correct format."""
44+
date_pattern = re.compile(r'^\d{4}-\d{2}-\d{2}$')
45+
for d in dates:
46+
if not date_pattern.match(d):
47+
raise ValueError(f"Date {d} must be in YYYY-MM-DD format")
48+
return dates
49+
1350
class TaskRequest(BaseModel):
51+
"""Model for task creation requests."""
52+
description: str = Field(...,
53+
description="Task description/title",
54+
examples=["Complete project proposal"])
55+
assigned_to: str = Field(...,
56+
description="Person assigned to this task",
57+
examples=["John Smith"])
58+
deadline: str = Field(...,
59+
description="Task deadline in YYYY-MM-DD format",
60+
examples=["2025-04-15"])
61+
priority: Priority = Field(Priority.MEDIUM,
62+
description="Task priority level")
63+
64+
@field_validator('deadline')
65+
def validate_deadline(cls, deadline):
66+
"""Ensure deadline is in the correct format."""
67+
try:
68+
datetime.strptime(deadline, "%Y-%m-%d")
69+
return deadline
70+
except ValueError:
71+
raise ValueError("Deadline must be in YYYY-MM-DD format")
72+
73+
# Response models for consistent API responses
74+
class AnalysisResponse(BaseModel):
75+
"""Standard response for AI analysis requests."""
76+
analysis: str
77+
timestamp: datetime = Field(default_factory=datetime.now)
78+
79+
class TaskResponse(BaseModel):
80+
"""Standard response model for task operations."""
81+
id: str
1482
description: str
1583
assigned_to: str
1684
deadline: str
17-
priority: Optional[str] = "Medium"
85+
priority: str
86+
status: str
87+
analysis: Optional[str] = None
88+
tags: Optional[List[str]] = None
89+
created_at: str
90+
updated_at: Optional[str] = None
91+
92+
class EmailProcessResponse(BaseModel):
93+
"""Response model for email processing."""
94+
analysis: str
95+
actions_taken: List[Dict[str, Any]]
96+
97+
class MeetingScheduleResponse(BaseModel):
98+
"""Response model for meeting scheduling."""
99+
recommendation: str
100+
event_created: bool
101+
event_details: Dict[str, Any]
102+
scheduled_time: Dict[str, str]

‎backend/data/tasks.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[
2+
{
3+
"id": "task_1742498524",
4+
"description": "Complete project proposal",
5+
"assigned_to": "John Smith",
6+
"deadline": "2025-04-15",
7+
"priority": "High",
8+
"status": "Done",
9+
"analysis": "This is a high priority task with creation deadline approaching. I recommend immediate focus to outline key project sections. Allocate approximately 4 hours for initial draft creation, followed by 2 hours for review and revision. Notify project manager upon completion for feedback integration.",
10+
"created_at": "2025-03-20T22:22:04.266193",
11+
"updated_at": "2025-03-20T22:39:09.910434"
12+
},
13+
{
14+
"id": "task_1742498555",
15+
"description": "Complete project proposal",
16+
"assigned_to": "John Smith",
17+
"deadline": "2025-04-15",
18+
"priority": "High",
19+
"status": "To Do",
20+
"analysis": "This is a high priority task assigned to John Smith with a impending deadline. I recommend immediate action to outline the project scope and key deliverables. John should focus on research, planning, and drafting the proposal today, aiming for completion by tomorrow.",
21+
"created_at": "2025-03-20T22:22:35.222861"
22+
},
23+
{
24+
"id": "task_1742499620",
25+
"description": "Fix critical server outage",
26+
"assigned_to": "IT Support",
27+
"deadline": "2025-03-25",
28+
"priority": "Urgent",
29+
"status": "To Do",
30+
"tags": [
31+
"Urgent",
32+
"Due This Week"
33+
],
34+
"analysis": "This is an urgent task requiring immediate attention. The IT Support team should focus on resolving the server outage problem promptly. Other non-critical tasks should be postponed to prioritize this issue.",
35+
"created_at": "2025-03-20T22:40:20.122205"
36+
}
37+
]

‎backend/integrations/trello_service.py

-170
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.