VACInc commited on
Commit
d77faa0
·
1 Parent(s): 21314b5
Files changed (2) hide show
  1. app.py +398 -44
  2. requirements.txt +7 -5
app.py CHANGED
@@ -1,64 +1,418 @@
1
- from smolagents import CodeAgent,DuckDuckGoSearchTool, HfApiModel,load_tool,tool
2
- import datetime
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import requests
4
- import pytz
5
- import yaml
6
- from tools.final_answer import FinalAnswerTool
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- from Gradio_UI import GradioUI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  @tool
11
- def my_custom_tool(arg1:str, arg2:int)-> str: #it's import to specify the return type
12
- #Keep this format for the description / args / args description but feel free to modify the tool
13
- """A tool that does nothing yet
 
14
  Args:
15
- arg1: the first argument
16
- arg2: the second argument
 
 
 
 
17
  """
18
- return "What magic will you build ?"
19
 
20
  @tool
21
- def get_current_time_in_timezone(timezone: str) -> str:
22
- """A tool that fetches the current local time in a specified timezone.
 
 
 
 
 
 
 
 
 
 
 
 
23
  Args:
24
- timezone: A string representing a valid timezone (e.g., 'America/New_York').
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  """
26
  try:
27
- # Create timezone object
28
- tz = pytz.timezone(timezone)
29
- # Get current time in that timezone
30
- local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
31
- return f"The current local time in {timezone} is: {local_time}"
 
 
 
 
 
 
 
 
 
32
  except Exception as e:
33
- return f"Error fetching time for timezone '{timezone}': {str(e)}"
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
- final_answer = FinalAnswerTool()
37
- model = HfApiModel(
38
- max_tokens=2096,
39
- temperature=0.5,
40
- model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
41
- custom_role_conversions=None,
42
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
- # Import tool from Hub
46
- image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
47
 
48
- with open("prompts.yaml", 'r') as stream:
49
- prompt_templates = yaml.safe_load(stream)
 
 
 
 
 
50
 
51
- agent = CodeAgent(
52
- model=model,
53
- tools=[image_generation_tool,get_current_time_in_timezone,final_answer,DuckDuckGoSearchTool()], ## add or remove tools here
54
- max_steps=6,
55
- verbosity_level=1,
56
- grammar=None,
57
- planning_interval=None,
58
- name=None,
59
- description=None,
60
- prompt_templates=prompt_templates
61
- )
 
 
 
 
 
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
- GradioUI(agent).launch()
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Personal Productivity Assistant Agent
4
+ Built using smolagents framework following HuggingFace Agents Course
5
+
6
+ USAGE:
7
+ 1. pip install -r requirements.txt
8
+ 2. export HF_TOKEN=your_huggingface_token
9
+ 3. python app.py
10
+
11
+ OR deploy to HuggingFace Spaces directly!
12
+ """
13
+
14
+ import os
15
+ import json
16
  import requests
17
+ import datetime
18
+ from typing import List, Dict, Optional
19
+ import gradio as gr
20
+ from dataclasses import dataclass
21
+
22
+ # smolagents imports
23
+ from smolagents import (
24
+ CodeAgent,
25
+ DuckDuckGoSearchTool,
26
+ InferenceClientModel,
27
+ tool,
28
+ Tool
29
+ )
30
+
31
+ # Set your HuggingFace token here
32
+ HF_TOKEN = os.getenv("HF_TOKEN", "your_hf_token_here")
33
+
34
+ @dataclass
35
+ class Task:
36
+ """Simple task representation"""
37
+ id: str
38
+ title: str
39
+ description: str
40
+ due_date: Optional[str] = None
41
+ completed: bool = False
42
 
43
+ class TaskManager:
44
+ """Simple in-memory task management"""
45
+ def __init__(self):
46
+ self.tasks = []
47
+ self.next_id = 1
48
+
49
+ def add_task(self, title: str, description: str, due_date: str = None) -> str:
50
+ task = Task(
51
+ id=str(self.next_id),
52
+ title=title,
53
+ description=description,
54
+ due_date=due_date
55
+ )
56
+ self.tasks.append(task)
57
+ self.next_id += 1
58
+ return f"Task '{title}' added with ID {task.id}"
59
+
60
+ def list_tasks(self) -> str:
61
+ if not self.tasks:
62
+ return "No tasks found."
63
+
64
+ result = "Current Tasks:\n"
65
+ for task in self.tasks:
66
+ status = "✅" if task.completed else "⏳"
67
+ due_info = f" (Due: {task.due_date})" if task.due_date else ""
68
+ result += f"{status} [{task.id}] {task.title}{due_info}\n"
69
+ return result
70
+
71
+ def complete_task(self, task_id: str) -> str:
72
+ for task in self.tasks:
73
+ if task.id == task_id:
74
+ task.completed = True
75
+ return f"Task '{task.title}' marked as completed!"
76
+ return f"Task with ID {task_id} not found."
77
+
78
+ # Global task manager instance
79
+ task_manager = TaskManager()
80
 
81
  @tool
82
+ def add_task(title: str, description: str, due_date: str = None) -> str:
83
+ """
84
+ Add a new task to the task list.
85
+
86
  Args:
87
+ title: Task title
88
+ description: Task description
89
+ due_date: Optional due date in YYYY-MM-DD format
90
+
91
+ Returns:
92
+ Confirmation message
93
  """
94
+ return task_manager.add_task(title, description, due_date)
95
 
96
  @tool
97
+ def list_tasks() -> str:
98
+ """
99
+ List all current tasks with their status.
100
+
101
+ Returns:
102
+ Formatted list of tasks
103
+ """
104
+ return task_manager.list_tasks()
105
+
106
+ @tool
107
+ def complete_task(task_id: str) -> str:
108
+ """
109
+ Mark a task as completed.
110
+
111
  Args:
112
+ task_id: ID of the task to complete
113
+
114
+ Returns:
115
+ Confirmation message
116
+ """
117
+ return task_manager.complete_task(task_id)
118
+
119
+ @tool
120
+ def get_current_time() -> str:
121
+ """
122
+ Get the current date and time.
123
+
124
+ Returns:
125
+ Current date and time formatted string
126
+ """
127
+ now = datetime.datetime.now()
128
+ return f"Current time: {now.strftime('%Y-%m-%d %H:%M:%S')}"
129
+
130
+ @tool
131
+ def calculate_days_until(target_date: str) -> str:
132
+ """
133
+ Calculate days between today and a target date.
134
+
135
+ Args:
136
+ target_date: Date in YYYY-MM-DD format
137
+
138
+ Returns:
139
+ Number of days until target date
140
+ """
141
+ try:
142
+ today = datetime.date.today()
143
+ target = datetime.datetime.strptime(target_date, '%Y-%m-%d').date()
144
+ days_diff = (target - today).days
145
+
146
+ if days_diff > 0:
147
+ return f"{days_diff} days until {target_date}"
148
+ elif days_diff == 0:
149
+ return f"{target_date} is today!"
150
+ else:
151
+ return f"{target_date} was {abs(days_diff)} days ago"
152
+ except ValueError:
153
+ return "Invalid date format. Please use YYYY-MM-DD."
154
+
155
+ @tool
156
+ def get_weather_info(city: str) -> str:
157
+ """
158
+ Get weather information for a city using a free weather API.
159
+
160
+ Args:
161
+ city: City name
162
+
163
+ Returns:
164
+ Weather information string
165
  """
166
  try:
167
+ # Using OpenWeatherMap API (you'd need to sign up for a free API key)
168
+ # For demo purposes, returning mock data
169
+ mock_weather = {
170
+ "london": "London: 15°C, Cloudy, 60% humidity",
171
+ "new york": "New York: 22°C, Sunny, 45% humidity",
172
+ "paris": "Paris: 18°C, Light rain, 70% humidity",
173
+ "tokyo": "Tokyo: 25°C, Partly cloudy, 55% humidity"
174
+ }
175
+
176
+ city_lower = city.lower()
177
+ if city_lower in mock_weather:
178
+ return mock_weather[city_lower]
179
+ else:
180
+ return f"Weather data for {city}: 20°C, Clear skies, 50% humidity (Mock data)"
181
  except Exception as e:
182
+ return f"Could not fetch weather for {city}: {str(e)}"
183
 
184
+ @tool
185
+ def send_mock_email(recipient: str, subject: str, body: str) -> str:
186
+ """
187
+ Send a mock email (simulation only).
188
+
189
+ Args:
190
+ recipient: Email recipient
191
+ subject: Email subject
192
+ body: Email body content
193
+
194
+ Returns:
195
+ Confirmation message
196
+ """
197
+ return f"Mock email sent to {recipient}\nSubject: {subject}\nBody preview: {body[:50]}..."
198
 
199
+ @tool
200
+ def create_meeting_summary(attendees: str, topic: str, duration_minutes: int) -> str:
201
+ """
202
+ Create a meeting summary template.
203
+
204
+ Args:
205
+ attendees: Comma-separated list of attendees
206
+ topic: Meeting topic
207
+ duration_minutes: Meeting duration in minutes
208
+
209
+ Returns:
210
+ Meeting summary template
211
+ """
212
+ now = datetime.datetime.now()
213
+ end_time = now + datetime.timedelta(minutes=duration_minutes)
214
+
215
+ summary = f"""
216
+ MEETING SUMMARY TEMPLATE
217
+ ========================
218
+ Date: {now.strftime('%Y-%m-%d')}
219
+ Time: {now.strftime('%H:%M')} - {end_time.strftime('%H:%M')}
220
+ Duration: {duration_minutes} minutes
221
+ Topic: {topic}
222
+ Attendees: {attendees}
223
+
224
+ AGENDA:
225
+ - [ ] Welcome and introductions
226
+ - [ ] Main topic discussion
227
+ - [ ] Action items
228
+ - [ ] Next steps
229
+
230
+ NOTES:
231
+ [Add meeting notes here]
232
+
233
+ ACTION ITEMS:
234
+ - [ ] [Action item 1 - Assignee]
235
+ - [ ] [Action item 2 - Assignee]
236
+
237
+ NEXT MEETING: [Date/Time]
238
+ """
239
+ return summary
240
 
241
+ class PersonalProductivityAgent:
242
+ """Main productivity agent class"""
243
+
244
+ def __init__(self):
245
+ # Initialize the model
246
+ self.model = InferenceClientModel(
247
+ model="Qwen/Qwen2.5-Coder-32B-Instruct",
248
+ token=HF_TOKEN
249
+ )
250
+
251
+ # Initialize tools
252
+ self.search_tool = DuckDuckGoSearchTool()
253
+
254
+ # Create custom tools list
255
+ self.custom_tools = [
256
+ add_task,
257
+ list_tasks,
258
+ complete_task,
259
+ get_current_time,
260
+ calculate_days_until,
261
+ get_weather_info,
262
+ send_mock_email,
263
+ create_meeting_summary
264
+ ]
265
+
266
+ # Initialize the CodeAgent
267
+ self.agent = CodeAgent(
268
+ tools=[self.search_tool] + self.custom_tools,
269
+ model=self.model,
270
+ add_base_tools=True, # Adds basic tools like Python execution
271
+ planning_interval=3 # Plan every 3 steps
272
+ )
273
+
274
+ # System prompt customization
275
+ self.agent.system_prompt = """You are an advanced Personal Productivity Assistant named Alfred.
276
+
277
+ You help users manage their daily tasks, schedule, communications, and information needs.
278
+
279
+ Key capabilities:
280
+ - Task management (add, list, complete tasks)
281
+ - Time and date calculations
282
+ - Weather information
283
+ - Web search and research
284
+ - Email composition (mock)
285
+ - Meeting planning and templates
286
+ - General calculations and code execution
287
+
288
+ Always be helpful, concise, and proactive in suggesting productivity improvements.
289
+ When users ask for help, offer multiple options and explain your reasoning.
290
+ """
291
+
292
+ def run(self, query: str, reset_memory: bool = False) -> str:
293
+ """Run the agent with a user query"""
294
+ try:
295
+ response = self.agent.run(query, reset=reset_memory)
296
+ return str(response)
297
+ except Exception as e:
298
+ return f"I apologize, but I encountered an error: {str(e)}"
299
 
300
+ # Initialize the global agent
301
+ productivity_agent = PersonalProductivityAgent()
302
 
303
+ def chat_interface(message, history, reset_conversation):
304
+ """Gradio chat interface function"""
305
+ if reset_conversation:
306
+ # Reset the conversation memory
307
+ response = productivity_agent.run(message, reset_memory=True)
308
+ else:
309
+ response = productivity_agent.run(message, reset_memory=False)
310
 
311
+ history.append([message, response])
312
+ return history, ""
313
+
314
+ def demo_queries():
315
+ """Return a list of demo queries users can try"""
316
+ return [
317
+ "Add a task to review the quarterly report by 2025-07-15",
318
+ "What's the weather like in London today?",
319
+ "List all my current tasks",
320
+ "How many days until Christmas 2025?",
321
+ "Search for the latest AI agent research papers",
322
+ "Create a meeting summary for a 1-hour team standup with John, Sarah, and Mike",
323
+ "Calculate 15% of 50000 and explain the tax implications",
324
+ "Complete task 1",
325
+ "Send a mock email to manager@company.com about project status"
326
+ ]
327
 
328
+ # Gradio Interface
329
+ def create_gradio_interface():
330
+ """Create the Gradio interface"""
331
+
332
+ with gr.Blocks(title="Personal Productivity Assistant", theme=gr.themes.Soft()) as demo:
333
+ gr.Markdown("""
334
+ # 🤖 Personal Productivity Assistant (Alfred)
335
+
336
+ Your AI-powered productivity companion built with smolagents framework.
337
+
338
+ **Capabilities:**
339
+ - 📋 Task Management (add, list, complete)
340
+ - 🌤️ Weather Information
341
+ - 📅 Date/Time Calculations
342
+ - 🔍 Web Search & Research
343
+ - 📧 Email Composition (mock)
344
+ - 📊 Meeting Templates
345
+ - 🧮 Code Execution & Calculations
346
+ """)
347
+
348
+ with gr.Row():
349
+ with gr.Column(scale=3):
350
+ chatbot = gr.Chatbot(
351
+ label="Chat with Alfred",
352
+ height=500,
353
+ show_label=True
354
+ )
355
+
356
+ with gr.Row():
357
+ msg = gr.Textbox(
358
+ label="Message",
359
+ placeholder="Ask me anything about productivity, tasks, weather, or research...",
360
+ scale=4
361
+ )
362
+ submit_btn = gr.Button("Send", variant="primary", scale=1)
363
+
364
+ reset_btn = gr.Button("Reset Conversation", variant="secondary")
365
+
366
+ with gr.Column(scale=1):
367
+ gr.Markdown("### 💡 Try These Examples:")
368
+
369
+ example_queries = demo_queries()
370
+ for query in example_queries:
371
+ gr.Button(
372
+ query,
373
+ size="sm"
374
+ ).click(
375
+ lambda q=query: (q, ""),
376
+ outputs=[msg, msg]
377
+ )
378
+
379
+ # Event handlers
380
+ submit_btn.click(
381
+ chat_interface,
382
+ inputs=[msg, chatbot, gr.State(False)],
383
+ outputs=[chatbot, msg]
384
+ )
385
+
386
+ msg.submit(
387
+ chat_interface,
388
+ inputs=[msg, chatbot, gr.State(False)],
389
+ outputs=[chatbot, msg]
390
+ )
391
+
392
+ reset_btn.click(
393
+ lambda: ([], ""),
394
+ outputs=[chatbot, msg]
395
+ )
396
+
397
+ gr.Markdown("""
398
+ ---
399
+ **Built with:** smolagents • HuggingFace • Qwen2.5-Coder-32B-Instruct
400
+
401
+ **Features Demonstrated:**
402
+ - CodeAgent with custom tools
403
+ - Multi-tool orchestration
404
+ - Memory management
405
+ - Real-world productivity use cases
406
+ """)
407
+
408
+ return demo
409
 
410
+ if __name__ == "__main__":
411
+ # Create and launch the interface
412
+ demo = create_gradio_interface()
413
+ demo.launch(
414
+ share=True,
415
+ debug=True,
416
+ server_name="0.0.0.0",
417
+ server_port=7860
418
+ )
requirements.txt CHANGED
@@ -1,5 +1,7 @@
1
- markdownify
2
- smolagents==1.13.0
3
- requests
4
- duckduckgo_search
5
- pandas
 
 
 
1
+ smolagents>=0.4.0
2
+ gradio>=4.0.0
3
+ huggingface_hub>=0.19.0
4
+ transformers>=4.35.0
5
+ torch>=2.0.0
6
+ requests>=2.31.0
7
+ python-dateutil>=2.8.2