Berry18 commited on
Commit
2650708
·
verified ·
1 Parent(s): 81917a3

Upload 5 files

Browse files
Files changed (5) hide show
  1. README.md +35 -15
  2. app.py +101 -188
  3. requirements.txt +4 -2
  4. task_manager_agent.py +336 -0
  5. taskm.jsonl +5 -0
README.md CHANGED
@@ -1,15 +1,35 @@
1
- ---
2
- title: Template Final Assignment
3
- emoji: 🕵🏻‍♂️
4
- colorFrom: indigo
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 5.25.2
8
- app_file: app.py
9
- pinned: false
10
- hf_oauth: true
11
- # optional, default duration is 8 hours/480 minutes. Max duration is 30 days/43200 minutes.
12
- hf_oauth_expiration_minutes: 480
13
- ---
14
-
15
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Space - Personal Task Manager Agent
2
+
3
+ This repository contains a Personal Task Manager Agent created for the Hugging Face AI Agent Course final project.
4
+
5
+ ## Project Overview
6
+
7
+ The Personal Task Manager Agent helps users manage tasks through natural language commands. It can:
8
+ - Add new tasks with details like priority, due date, and category
9
+ - List all tasks or filter by category/priority
10
+ - Mark tasks as complete
11
+ - Delete tasks
12
+ - Provide help information
13
+
14
+ ## Files in this Repository
15
+
16
+ - `task_manager_agent.py`: Core agent implementation with task management functionality
17
+ - `app.py`: Hugging Face Space implementation with Gradio UI and GAIA API endpoint
18
+ - `requirements.txt`: Required Python packages
19
+ - `README.md`: This documentation file
20
+
21
+ ## GAIA Benchmark Integration
22
+
23
+ This agent includes an API endpoint specifically designed for the GAIA benchmark evaluation. The endpoint processes questions from the benchmark and returns answers in the expected format.
24
+
25
+ ## How to Use
26
+
27
+ Interact with the agent using natural language commands in the chat interface. Here are some example commands:
28
+
29
+ - Add a task: "Add a new task to buy groceries"
30
+ - Add with details: "Add task to call mom priority:high due:2023-05-20 category:personal"
31
+ - List tasks: "Show me my tasks" or "What do I need to do?"
32
+ - Complete a task: "Mark task 2 as done" or "I completed task 3"
33
+ - Delete a task: "Delete task 1" or "Remove task 4"
34
+ - Filter tasks: "Show high priority tasks" or "List personal tasks"
35
+ - Get help: "Help me" or "What can you do?"
app.py CHANGED
@@ -1,196 +1,109 @@
1
- import os
 
 
 
 
2
  import gradio as gr
3
- import requests
4
- import inspect
5
- import pandas as pd
 
 
 
6
 
7
- # (Keep Constants as is)
8
- # --- Constants ---
9
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
 
11
- # --- Basic Agent Definition ---
12
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
13
- class BasicAgent:
14
- def __init__(self):
15
- print("BasicAgent initialized.")
16
- def __call__(self, question: str) -> str:
17
- print(f"Agent received question (first 50 chars): {question[:50]}...")
18
- fixed_answer = "This is a default answer."
19
- print(f"Agent returning fixed answer: {fixed_answer}")
20
- return fixed_answer
21
 
22
- def run_and_submit_all( profile: gr.OAuthProfile | None):
23
  """
24
- Fetches all questions, runs the BasicAgent on them, submits all answers,
25
- and displays the results.
26
  """
27
- # --- Determine HF Space Runtime URL and Repo URL ---
28
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
29
-
30
- if profile:
31
- username= f"{profile.username}"
32
- print(f"User logged in: {username}")
33
- else:
34
- print("User not logged in.")
35
- return "Please Login to Hugging Face with the button.", None
36
-
37
- api_url = DEFAULT_API_URL
38
- questions_url = f"{api_url}/questions"
39
- submit_url = f"{api_url}/submit"
40
-
41
- # 1. Instantiate Agent ( modify this part to create your agent)
42
- try:
43
- agent = BasicAgent()
44
- except Exception as e:
45
- print(f"Error instantiating agent: {e}")
46
- return f"Error initializing agent: {e}", None
47
- # In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)
48
- agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
49
- print(agent_code)
50
-
51
- # 2. Fetch Questions
52
- print(f"Fetching questions from: {questions_url}")
53
- try:
54
- response = requests.get(questions_url, timeout=15)
55
- response.raise_for_status()
56
- questions_data = response.json()
57
- if not questions_data:
58
- print("Fetched questions list is empty.")
59
- return "Fetched questions list is empty or invalid format.", None
60
- print(f"Fetched {len(questions_data)} questions.")
61
- except requests.exceptions.RequestException as e:
62
- print(f"Error fetching questions: {e}")
63
- return f"Error fetching questions: {e}", None
64
- except requests.exceptions.JSONDecodeError as e:
65
- print(f"Error decoding JSON response from questions endpoint: {e}")
66
- print(f"Response text: {response.text[:500]}")
67
- return f"Error decoding server response for questions: {e}", None
68
- except Exception as e:
69
- print(f"An unexpected error occurred fetching questions: {e}")
70
- return f"An unexpected error occurred fetching questions: {e}", None
71
-
72
- # 3. Run your Agent
73
- results_log = []
74
- answers_payload = []
75
- print(f"Running agent on {len(questions_data)} questions...")
76
- for item in questions_data:
77
- task_id = item.get("task_id")
78
- question_text = item.get("question")
79
- if not task_id or question_text is None:
80
- print(f"Skipping item with missing task_id or question: {item}")
81
- continue
82
- try:
83
- submitted_answer = agent(question_text)
84
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
85
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
86
- except Exception as e:
87
- print(f"Error running agent on task {task_id}: {e}")
88
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
89
-
90
- if not answers_payload:
91
- print("Agent did not produce any answers to submit.")
92
- return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
93
-
94
- # 4. Prepare Submission
95
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
96
- status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
97
- print(status_update)
98
-
99
- # 5. Submit
100
- print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
101
- try:
102
- response = requests.post(submit_url, json=submission_data, timeout=60)
103
- response.raise_for_status()
104
- result_data = response.json()
105
- final_status = (
106
- f"Submission Successful!\n"
107
- f"User: {result_data.get('username')}\n"
108
- f"Overall Score: {result_data.get('score', 'N/A')}% "
109
- f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
110
- f"Message: {result_data.get('message', 'No message received.')}"
111
- )
112
- print("Submission successful.")
113
- results_df = pd.DataFrame(results_log)
114
- return final_status, results_df
115
- except requests.exceptions.HTTPError as e:
116
- error_detail = f"Server responded with status {e.response.status_code}."
117
- try:
118
- error_json = e.response.json()
119
- error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
120
- except requests.exceptions.JSONDecodeError:
121
- error_detail += f" Response: {e.response.text[:500]}"
122
- status_message = f"Submission Failed: {error_detail}"
123
- print(status_message)
124
- results_df = pd.DataFrame(results_log)
125
- return status_message, results_df
126
- except requests.exceptions.Timeout:
127
- status_message = "Submission Failed: The request timed out."
128
- print(status_message)
129
- results_df = pd.DataFrame(results_log)
130
- return status_message, results_df
131
- except requests.exceptions.RequestException as e:
132
- status_message = f"Submission Failed: Network error - {e}"
133
- print(status_message)
134
- results_df = pd.DataFrame(results_log)
135
- return status_message, results_df
136
- except Exception as e:
137
- status_message = f"An unexpected error occurred during submission: {e}"
138
- print(status_message)
139
- results_df = pd.DataFrame(results_log)
140
- return status_message, results_df
141
-
142
-
143
- # --- Build Gradio Interface using Blocks ---
144
- with gr.Blocks() as demo:
145
- gr.Markdown("# Basic Agent Evaluation Runner")
146
- gr.Markdown(
147
- """
148
- **Instructions:**
149
-
150
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
151
- 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
152
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
153
-
154
- ---
155
- **Disclaimers:**
156
- Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
157
- This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.
158
- """
159
  )
160
-
161
- gr.LoginButton()
162
-
163
- run_button = gr.Button("Run Evaluation & Submit All Answers")
164
-
165
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
166
- # Removed max_rows=10 from DataFrame constructor
167
- results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
168
-
169
- run_button.click(
170
- fn=run_and_submit_all,
171
- outputs=[status_output, results_table]
172
- )
173
-
 
 
 
 
 
 
174
  if __name__ == "__main__":
175
- print("\n" + "-"*30 + " App Starting " + "-"*30)
176
- # Check for SPACE_HOST and SPACE_ID at startup for information
177
- space_host_startup = os.getenv("SPACE_HOST")
178
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
179
-
180
- if space_host_startup:
181
- print(f"✅ SPACE_HOST found: {space_host_startup}")
182
- print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
183
- else:
184
- print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
185
-
186
- if space_id_startup: # Print repo URLs if SPACE_ID is found
187
- print(f"✅ SPACE_ID found: {space_id_startup}")
188
- print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
189
- print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
190
- else:
191
- print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
192
-
193
- print("-"*(60 + len(" App Starting ")) + "\n")
194
-
195
- print("Launching Gradio Interface for Basic Agent Evaluation...")
196
- demo.launch(debug=True, share=False)
 
1
+ """
2
+ Hugging Face Space implementation for Personal Task Manager Agent
3
+ This file serves as the entry point for the Hugging Face Space
4
+ """
5
+
6
  import gradio as gr
7
+ from task_manager_agent import TaskManagerAgent
8
+ import json
9
+ import os
10
+
11
+ # Initialize the agent
12
+ agent = TaskManagerAgent()
13
 
14
+ # Try to load existing tasks if available
15
+ if os.path.exists("tasks.json"):
16
+ agent.load_state("tasks.json")
17
 
18
+ def process_message(message, history):
19
+ """Process user message and return agent response"""
20
+ response = agent.process_query(message)
21
+
22
+ # Save state after each interaction
23
+ agent.save_state("tasks.json")
24
+
25
+ return response
 
 
26
 
27
+ def get_gaia_answer(question):
28
  """
29
+ Function to process GAIA benchmark questions
30
+ This is the function that will be called by the GAIA API
31
  """
32
+ # Process the question with our agent
33
+ response = agent.process_query(question)
34
+
35
+ # For GAIA benchmark, we need to return just the answer without any formatting
36
+ # Strip any extra formatting that might be in the response
37
+ clean_response = response.strip()
38
+
39
+ return clean_response
40
+
41
+ # Create Gradio interface
42
+ with gr.Blocks(title="Personal Task Manager Agent") as demo:
43
+ gr.Markdown("# Personal Task Manager Agent")
44
+ gr.Markdown("""
45
+ This agent helps you manage tasks through natural language commands.
46
+
47
+ ## Example commands:
48
+ - Add a task: "Add a new task to buy groceries"
49
+ - Add with details: "Add task to call mom priority:high due:2023-05-20 category:personal"
50
+ - List tasks: "Show me my tasks" or "What do I need to do?"
51
+ - Complete a task: "Mark task 2 as done" or "I completed task 3"
52
+ - Delete a task: "Delete task 1" or "Remove task 4"
53
+ - Filter tasks: "Show high priority tasks" or "List personal tasks"
54
+ - Get help: "Help me" or "What can you do?"
55
+ """)
56
+
57
+ chatbot = gr.Chatbot(height=400)
58
+ msg = gr.Textbox(label="Type your command here")
59
+ clear = gr.Button("Clear")
60
+
61
+ def user(message, history):
62
+ return "", history + [[message, None]]
63
+
64
+ def bot(history):
65
+ message = history[-1][0]
66
+ response = process_message(message, history)
67
+ history[-1][1] = response
68
+ return history
69
+
70
+ msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(
71
+ bot, chatbot, chatbot
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  )
73
+
74
+ clear.click(lambda: None, None, chatbot, queue=False)
75
+
76
+ # Add GAIA API endpoint explanation
77
+ gr.Markdown("""
78
+ ## GAIA Benchmark API
79
+
80
+ This Space includes an API endpoint for the GAIA benchmark. The API processes questions
81
+ and returns answers in the format expected by the benchmark.
82
+
83
+ The endpoint is automatically available when deployed on Hugging Face Spaces.
84
+ """)
85
+
86
+ # For GAIA API endpoint
87
+ def gaia_api(question):
88
+ """API endpoint for GAIA benchmark"""
89
+ answer = get_gaia_answer(question)
90
+ return {"answer": answer}
91
+
92
+ # Launch the app
93
  if __name__ == "__main__":
94
+ # Set up FastAPI for GAIA benchmark
95
+ from fastapi import FastAPI, Request
96
+ import uvicorn
97
+ from pydantic import BaseModel
98
+
99
+ app = FastAPI()
100
+
101
+ class Question(BaseModel):
102
+ question: str
103
+
104
+ @app.post("/api/gaia")
105
+ async def api_gaia(question: Question):
106
+ return gaia_api(question.question)
107
+
108
+ # Mount Gradio app
109
+ demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,2 +1,4 @@
1
- gradio
2
- requests
 
 
 
1
+ gradio==4.0.2
2
+ fastapi==0.104.1
3
+ uvicorn==0.23.2
4
+ pydantic==2.4.2
task_manager_agent.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Personal Task Manager Agent for Hugging Face AI Agent Course Final Project
3
+
4
+ This agent helps users manage tasks, set priorities, and organize information
5
+ through natural language understanding and simple task management functionality.
6
+ """
7
+
8
+ import json
9
+ import re
10
+ import datetime
11
+ from typing import List, Dict, Any, Optional, Tuple
12
+
13
+ class Task:
14
+ """Represents a single task with properties like description, priority, due date, etc."""
15
+
16
+ def __init__(self, description: str, priority: str = "medium",
17
+ due_date: Optional[str] = None, category: str = "general"):
18
+ self.description = description
19
+ self.priority = priority.lower() # "high", "medium", or "low"
20
+ self.due_date = due_date # Format: YYYY-MM-DD
21
+ self.category = category.lower()
22
+ self.completed = False
23
+ self.creation_date = datetime.datetime.now().strftime("%Y-%m-%d")
24
+
25
+ def to_dict(self) -> Dict[str, Any]:
26
+ """Convert task to dictionary for JSON serialization"""
27
+ return {
28
+ "description": self.description,
29
+ "priority": self.priority,
30
+ "due_date": self.due_date,
31
+ "category": self.category,
32
+ "completed": self.completed,
33
+ "creation_date": self.creation_date
34
+ }
35
+
36
+ @classmethod
37
+ def from_dict(cls, data: Dict[str, Any]) -> 'Task':
38
+ """Create a Task object from a dictionary"""
39
+ task = cls(
40
+ description=data["description"],
41
+ priority=data["priority"],
42
+ due_date=data["due_date"],
43
+ category=data["category"]
44
+ )
45
+ task.completed = data["completed"]
46
+ task.creation_date = data["creation_date"]
47
+ return task
48
+
49
+ def __str__(self) -> str:
50
+ """String representation of the task"""
51
+ status = "✓" if self.completed else "□"
52
+ due_str = f" (Due: {self.due_date})" if self.due_date else ""
53
+ return f"{status} [{self.priority.upper()}] {self.description}{due_str} - {self.category}"
54
+
55
+
56
+ class TaskManager:
57
+ """Manages a collection of tasks with functionality to add, update, and query tasks"""
58
+
59
+ def __init__(self):
60
+ self.tasks: List[Task] = []
61
+
62
+ def add_task(self, task: Task) -> int:
63
+ """Add a new task and return its index"""
64
+ self.tasks.append(task)
65
+ return len(self.tasks) - 1
66
+
67
+ def update_task(self, index: int, **kwargs) -> bool:
68
+ """Update task properties at the given index"""
69
+ if 0 <= index < len(self.tasks):
70
+ task = self.tasks[index]
71
+ for key, value in kwargs.items():
72
+ if hasattr(task, key):
73
+ setattr(task, key, value)
74
+ return True
75
+ return False
76
+
77
+ def complete_task(self, index: int) -> bool:
78
+ """Mark a task as completed"""
79
+ return self.update_task(index, completed=True)
80
+
81
+ def delete_task(self, index: int) -> bool:
82
+ """Delete a task at the given index"""
83
+ if 0 <= index < len(self.tasks):
84
+ self.tasks.pop(index)
85
+ return True
86
+ return False
87
+
88
+ def get_tasks(self,
89
+ category: Optional[str] = None,
90
+ priority: Optional[str] = None,
91
+ completed: Optional[bool] = None) -> List[Tuple[int, Task]]:
92
+ """Get tasks with optional filtering, returns list of (index, task) tuples"""
93
+ result = []
94
+ for i, task in enumerate(self.tasks):
95
+ if (category is None or task.category == category.lower()) and \
96
+ (priority is None or task.priority == priority.lower()) and \
97
+ (completed is None or task.completed == completed):
98
+ result.append((i, task))
99
+ return result
100
+
101
+ def get_all_tasks(self) -> List[Tuple[int, Task]]:
102
+ """Get all tasks with their indices"""
103
+ return [(i, task) for i, task in enumerate(self.tasks)]
104
+
105
+ def get_categories(self) -> List[str]:
106
+ """Get list of unique categories"""
107
+ return list(set(task.category for task in self.tasks))
108
+
109
+ def save_to_file(self, filename: str) -> bool:
110
+ """Save tasks to a JSON file"""
111
+ try:
112
+ with open(filename, 'w') as f:
113
+ json.dump([task.to_dict() for task in self.tasks], f, indent=2)
114
+ return True
115
+ except Exception as e:
116
+ print(f"Error saving tasks: {e}")
117
+ return False
118
+
119
+ def load_from_file(self, filename: str) -> bool:
120
+ """Load tasks from a JSON file"""
121
+ try:
122
+ with open(filename, 'r') as f:
123
+ data = json.load(f)
124
+ self.tasks = [Task.from_dict(item) for item in data]
125
+ return True
126
+ except Exception as e:
127
+ print(f"Error loading tasks: {e}")
128
+ return False
129
+
130
+
131
+ class TaskManagerAgent:
132
+ """
133
+ AI agent that understands natural language requests related to task management
134
+ and performs appropriate actions using the TaskManager.
135
+ """
136
+
137
+ def __init__(self):
138
+ self.task_manager = TaskManager()
139
+ # Common patterns for understanding user intent
140
+ self.patterns = {
141
+ "add_task": [
142
+ r"add (?:a )?(?:new )?task(?: to)?(?: do)?(?: called)?(?: to)?(?: about)? (.+)",
143
+ r"create (?:a )?(?:new )?task(?: to)?(?: do)?(?: called)?(?: to)?(?: about)? (.+)",
144
+ r"remind me to (.+)",
145
+ ],
146
+ "list_tasks": [
147
+ r"(?:show|list|display|get)(?: all)?(?: my)? tasks",
148
+ r"what (?:are my|do i have for) tasks",
149
+ r"show me what i need to do",
150
+ ],
151
+ "complete_task": [
152
+ r"(?:mark|set) task (?:number )?(\d+) (?:as )?(?:done|complete|finished)",
153
+ r"complete task (?:number )?(\d+)",
154
+ r"i (?:have )?(?:done|completed|finished) task (?:number )?(\d+)",
155
+ ],
156
+ "delete_task": [
157
+ r"(?:delete|remove) task (?:number )?(\d+)",
158
+ r"get rid of task (?:number )?(\d+)",
159
+ ],
160
+ "filter_tasks": [
161
+ r"(?:show|list|display|get) (?:all )?(\w+) tasks",
162
+ r"(?:show|list|display|get) tasks (?:with|that are) (\w+)",
163
+ ],
164
+ "help": [
165
+ r"(?:help|assist|guide) me",
166
+ r"what can you do",
167
+ r"how do (?:you|i|this) work",
168
+ ]
169
+ }
170
+
171
+ def _extract_task_details(self, description: str) -> Dict[str, Any]:
172
+ """Extract task details like priority, due date, and category from description"""
173
+ details = {"description": description}
174
+
175
+ # Extract priority
176
+ priority_match = re.search(r"(?:priority|important|urgency):?\s*(high|medium|low)", description, re.I)
177
+ if priority_match:
178
+ details["priority"] = priority_match.group(1).lower()
179
+ # Remove the priority text from description
180
+ details["description"] = re.sub(r"(?:priority|important|urgency):?\s*(high|medium|low)", "", details["description"], flags=re.I).strip()
181
+
182
+ # Extract due date (simple format: YYYY-MM-DD or MM/DD/YYYY)
183
+ date_match = re.search(r"(?:due|by|on):?\s*(\d{4}-\d{2}-\d{2}|\d{1,2}/\d{1,2}/\d{4})", description, re.I)
184
+ if date_match:
185
+ date_str = date_match.group(1)
186
+ # Convert MM/DD/YYYY to YYYY-MM-DD if needed
187
+ if "/" in date_str:
188
+ month, day, year = date_str.split("/")
189
+ date_str = f"{year}-{month.zfill(2)}-{day.zfill(2)}"
190
+ details["due_date"] = date_str
191
+ # Remove the date text from description
192
+ details["description"] = re.sub(r"(?:due|by|on):?\s*(\d{4}-\d{2}-\d{2}|\d{1,2}/\d{1,2}/\d{4})", "", details["description"], flags=re.I).strip()
193
+
194
+ # Extract category
195
+ category_match = re.search(r"(?:category|tag|type):?\s*(\w+)", description, re.I)
196
+ if category_match:
197
+ details["category"] = category_match.group(1).lower()
198
+ # Remove the category text from description
199
+ details["description"] = re.sub(r"(?:category|tag|type):?\s*(\w+)", "", details["description"], flags=re.I).strip()
200
+
201
+ return details
202
+
203
+ def process_query(self, query: str) -> str:
204
+ """
205
+ Process a natural language query and perform the appropriate task management action.
206
+ Returns a response string.
207
+ """
208
+ # Check for intent matches
209
+ for intent, patterns in self.patterns.items():
210
+ for pattern in patterns:
211
+ match = re.search(pattern, query, re.I)
212
+ if match:
213
+ # Call the appropriate method based on intent
214
+ if intent == "add_task" and match.group(1):
215
+ return self._handle_add_task(match.group(1))
216
+ elif intent == "list_tasks":
217
+ return self._handle_list_tasks()
218
+ elif intent == "complete_task" and match.group(1):
219
+ return self._handle_complete_task(int(match.group(1)))
220
+ elif intent == "delete_task" and match.group(1):
221
+ return self._handle_delete_task(int(match.group(1)))
222
+ elif intent == "filter_tasks" and match.group(1):
223
+ return self._handle_filter_tasks(match.group(1))
224
+ elif intent == "help":
225
+ return self._handle_help()
226
+
227
+ # If no pattern matches, try to understand as a general query
228
+ return self._handle_general_query(query)
229
+
230
+ def _handle_add_task(self, description: str) -> str:
231
+ """Handle adding a new task"""
232
+ details = self._extract_task_details(description)
233
+ task = Task(
234
+ description=details["description"],
235
+ priority=details.get("priority", "medium"),
236
+ due_date=details.get("due_date"),
237
+ category=details.get("category", "general")
238
+ )
239
+ index = self.task_manager.add_task(task)
240
+ return f"Added task {index}: {task}"
241
+
242
+ def _handle_list_tasks(self) -> str:
243
+ """Handle listing all tasks"""
244
+ tasks = self.task_manager.get_all_tasks()
245
+ if not tasks:
246
+ return "You don't have any tasks yet."
247
+
248
+ result = "Here are your tasks:\n"
249
+ for index, task in tasks:
250
+ result += f"{index}: {task}\n"
251
+ return result
252
+
253
+ def _handle_complete_task(self, index: int) -> str:
254
+ """Handle marking a task as complete"""
255
+ if self.task_manager.complete_task(index):
256
+ return f"Marked task {index} as completed."
257
+ return f"Task {index} not found."
258
+
259
+ def _handle_delete_task(self, index: int) -> str:
260
+ """Handle deleting a task"""
261
+ if self.task_manager.delete_task(index):
262
+ return f"Deleted task {index}."
263
+ return f"Task {index} not found."
264
+
265
+ def _handle_filter_tasks(self, filter_term: str) -> str:
266
+ """Handle filtering tasks by category or priority"""
267
+ # Check if filter is a priority
268
+ if filter_term.lower() in ["high", "medium", "low"]:
269
+ tasks = self.task_manager.get_tasks(priority=filter_term.lower())
270
+ filter_type = "priority"
271
+ else:
272
+ # Assume it's a category
273
+ tasks = self.task_manager.get_tasks(category=filter_term.lower())
274
+ filter_type = "category"
275
+
276
+ if not tasks:
277
+ return f"No tasks found with {filter_type} '{filter_term}'."
278
+
279
+ result = f"Tasks with {filter_type} '{filter_term}':\n"
280
+ for index, task in tasks:
281
+ result += f"{index}: {task}\n"
282
+ return result
283
+
284
+ def _handle_help(self) -> str:
285
+ """Handle help request"""
286
+ return """
287
+ I can help you manage your tasks. Here's what you can ask me to do:
288
+
289
+ - Add a task: "Add a new task to buy groceries"
290
+ - Add with details: "Add task to call mom priority:high due:2023-05-20 category:personal"
291
+ - List tasks: "Show me my tasks" or "What do I need to do?"
292
+ - Complete a task: "Mark task 2 as done" or "I completed task 3"
293
+ - Delete a task: "Delete task 1" or "Remove task 4"
294
+ - Filter tasks: "Show high priority tasks" or "List personal tasks"
295
+ - Get help: "Help me" or "What can you do?"
296
+
297
+ Try one of these commands to get started!
298
+ """
299
+
300
+ def _handle_general_query(self, query: str) -> str:
301
+ """Handle queries that don't match specific patterns"""
302
+ # Check if it might be a task addition without explicit "add task" prefix
303
+ if not any(re.search(pattern, query, re.I) for patterns in self.patterns.values() for pattern in patterns):
304
+ # If query is short and looks like a task, add it
305
+ if len(query.split()) <= 10 and not query.endswith("?"):
306
+ return self._handle_add_task(query)
307
+
308
+ return f"I'm not sure how to help with '{query}'. Type 'help' to see what I can do."
309
+
310
+ def save_state(self, filename: str = "tasks.json") -> bool:
311
+ """Save the current state of tasks to a file"""
312
+ return self.task_manager.save_to_file(filename)
313
+
314
+ def load_state(self, filename: str = "tasks.json") -> bool:
315
+ """Load tasks from a file"""
316
+ return self.task_manager.load_from_file(filename)
317
+
318
+
319
+ # Example usage for testing
320
+ if __name__ == "__main__":
321
+ agent = TaskManagerAgent()
322
+
323
+ # Test with some example queries
324
+ test_queries = [
325
+ "add task to buy groceries",
326
+ "add task to call mom priority:high due:2023-05-20 category:personal",
327
+ "show my tasks",
328
+ "mark task 0 as done",
329
+ "show high priority tasks",
330
+ "help"
331
+ ]
332
+
333
+ for query in test_queries:
334
+ print(f"\nQuery: {query}")
335
+ response = agent.process_query(query)
336
+ print(f"Response: {response}")
taskm.jsonl ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {"task_id": "task_id_1", "model_answer": "Added task 0: □ [MEDIUM] buy groceries - general", "reasoning_trace": "The user asked to add a task to buy groceries. I processed this as a task addition request, created a new task with default priority (medium) and category (general), and added it to the task list."}
2
+ {"task_id": "task_id_2", "model_answer": "Added task 1: □ [HIGH] call mom (Due: 2023-05-20) - personal", "reasoning_trace": "The user asked to add a task with specific details. I extracted the priority (high), due date (2023-05-20), and category (personal) from the request and created a task with these parameters."}
3
+ {"task_id": "task_id_3", "model_answer": "Here are your tasks:\n0: □ [MEDIUM] buy groceries - general\n1: □ [HIGH] call mom (Due: 2023-05-20) - personal", "reasoning_trace": "The user asked to see their tasks. I retrieved all tasks from the task manager and formatted them as a numbered list showing the status, priority, description, due date (if any), and category."}
4
+ {"task_id": "task_id_4", "model_answer": "Marked task 0 as completed.", "reasoning_trace": "The user asked to mark task 0 as done. I updated the task's completed status to true and confirmed the action."}
5
+ {"task_id": "task_id_5", "model_answer": "Tasks with priority 'high':\n1: □ [HIGH] call mom (Due: 2023-05-20) - personal", "reasoning_trace": "The user asked to see high priority tasks. I filtered the tasks by priority='high' and returned the matching tasks as a formatted list."}