srinikhildurisetti commited on
Commit
efe51c1
·
1 Parent(s): 5057a0d

With UI changes and Server Fixes

Browse files
Files changed (5) hide show
  1. README.md +41 -10
  2. app.py +59 -18
  3. llm_parser.py +51 -19
  4. notion_handler.py +90 -37
  5. requirements.txt +5 -5
README.md CHANGED
@@ -11,22 +11,53 @@ pinned: false
11
 
12
  # 🧠 NotionTaskSense
13
 
14
- Turn vague goals into structured, actionable tasks and push them directly into Notion.
15
 
16
- ## ✨ What It Does
17
 
18
- You type messy thoughts like:
 
 
 
 
19
 
20
- > I want to fix my resume, apply to jobs, study cloud certs, and message seniors.
21
 
22
- And NotionTaskSense will:
 
 
 
23
 
24
- Understand your intent
25
- ✅ Break it into clear tasks
26
- ✅ Add categories, priorities, due dates
27
- ✅ Push each task into a clean Notion database
28
 
29
- No spreadsheets. No task lists. Just clarity.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  ---
32
 
 
11
 
12
  # 🧠 NotionTaskSense
13
 
14
+ NotionTaskSense is an AI-powered tool that helps you organize your goals into structured tasks in Notion. It uses natural language processing to break down your goals into actionable tasks and automatically creates them in your Notion workspace.
15
 
16
+ ## Features
17
 
18
+ - 🤖 AI-powered task breakdown
19
+ - 📝 Automatic Notion task creation
20
+ - 🎯 Smart task organization
21
+ - 🔄 Real-time processing
22
+ - 🌐 API access available
23
 
24
+ ## How to Use
25
 
26
+ 1. Enter your goals or tasks in natural language
27
+ 2. The AI will analyze and break them down into structured tasks
28
+ 3. Tasks are automatically created in your Notion workspace
29
+ 4. Access your organized tasks in Notion
30
 
31
+ ## API Usage
 
 
 
32
 
33
+ You can also use NotionTaskSense via its API endpoint:
34
+
35
+ ```bash
36
+ curl -X POST http://your-space-url/api/predict \
37
+ -H "Content-Type: application/json" \
38
+ -d '{"data": ["Your task description here"], "fn_index": 0}'
39
+ ```
40
+
41
+ ## Environment Variables Required
42
+
43
+ - `ANTHROPIC_API_KEY`: Your Anthropic API key for Claude
44
+ - `NOTION_API_KEY`: Your Notion integration token
45
+ - `NOTION_DATABASE_ID`: (Optional) Default Notion database ID
46
+
47
+ ## Local Development
48
+
49
+ 1. Clone the repository
50
+ 2. Install dependencies: `pip install -r requirements.txt`
51
+ 3. Set up environment variables
52
+ 4. Run the app: `python app.py`
53
+
54
+ ## Deployment
55
+
56
+ This app is deployed on Hugging Face Spaces and can be accessed at [space-url].
57
+
58
+ ## License
59
+
60
+ MIT License
61
 
62
  ---
63
 
app.py CHANGED
@@ -1,39 +1,80 @@
1
  import gradio as gr
2
  import os
 
 
 
 
 
 
3
 
4
  from llm_parser import llm_parse_tasks
5
  from notion_handler import create_tasks_database, push_tasks_to_notion
6
 
7
- def organize_goals_into_notion(user_input: str) -> str:
 
 
 
 
8
  try:
 
9
  tasks = llm_parse_tasks(user_input)
10
  if isinstance(tasks, str):
11
- return "Failed to parse tasks properly:\n\n" + tasks
 
 
 
 
 
12
 
13
  db_id = create_tasks_database()
14
  push_tasks_to_notion(tasks, db_id)
15
 
16
  task_names = [t.get("task", "Untitled") for t in tasks]
17
- return f" {len(task_names)} tasks added to Notion:\n- " + "\n- ".join(task_names)
 
 
 
 
 
 
18
  except Exception as e:
19
- return f" Error: {e}"
 
 
 
 
 
20
 
21
- # Gradio MCP app
22
- # with gr.Blocks() as demo:
23
- # gr.Markdown("# 🧠 NotionTaskSense – Turn your goals into Notion tasks")
24
- # inp = gr.Textbox(placeholder="What do you want to get done this week?", lines=4)
25
- # out = gr.Textbox(label="Agent Output")
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- # btn = gr.Button("Organize into Notion")
28
- # btn.click(fn=organize_goals_into_notion, inputs=inp, outputs=out)
 
 
 
29
 
30
- demo = gr.Interface(fn=organize_goals_into_notion,
31
- inputs=gr.Textbox(lines=4, placeholder="What do you want to get done this week?"),
32
- outputs=gr.Textbox(label="Agent Output"),
33
- title="🧠 NotionTaskSense",
34
- description="Turn your goals into Notion tasks")
 
35
 
36
 
37
 
38
- if __name__ == "__main__":
39
- demo.launch()
 
1
  import gradio as gr
2
  import os
3
+ from typing import Dict, List, Union, Any
4
+ import logging
5
+
6
+ # Configure logging
7
+ logging.basicConfig(level=logging.INFO)
8
+ logger = logging.getLogger(__name__)
9
 
10
  from llm_parser import llm_parse_tasks
11
  from notion_handler import create_tasks_database, push_tasks_to_notion
12
 
13
+ def organize_goals_into_notion(user_input: str) -> Dict[str, Any]:
14
+ """
15
+ Process a single goal into Notion tasks.
16
+ Returns a dictionary with success status and detailed response.
17
+ """
18
  try:
19
+ logger.info(f"Processing user input: {user_input}")
20
  tasks = llm_parse_tasks(user_input)
21
  if isinstance(tasks, str):
22
+ logger.error(f"Failed to parse tasks: {tasks}")
23
+ return {
24
+ "success": False,
25
+ "error": "Failed to parse tasks",
26
+ "details": tasks
27
+ }
28
 
29
  db_id = create_tasks_database()
30
  push_tasks_to_notion(tasks, db_id)
31
 
32
  task_names = [t.get("task", "Untitled") for t in tasks]
33
+ logger.info(f"Successfully created {len(task_names)} tasks")
34
+ return {
35
+ "success": True,
36
+ "message": f"✅ {len(task_names)} tasks added to Notion",
37
+ "tasks": task_names,
38
+ "database_id": db_id
39
+ }
40
  except Exception as e:
41
+ logger.error(f"Error processing request: {str(e)}")
42
+ return {
43
+ "success": False,
44
+ "error": str(e),
45
+ "details": "An error occurred while processing your request"
46
+ }
47
 
48
+ # Create Gradio interface
49
+ demo = gr.Interface(
50
+ fn=organize_goals_into_notion,
51
+ inputs=gr.Textbox(
52
+ lines=4,
53
+ placeholder="What do you want to get done this week?",
54
+ label="Your Goals"
55
+ ),
56
+ outputs=gr.JSON(label="Results"),
57
+ title="🧠 NotionTaskSense",
58
+ description="Turn your goals into structured Notion tasks",
59
+ examples=[
60
+ ["I need to update my resume, apply to 3 jobs, and study for AWS certification"],
61
+ ["Meet with team about project timeline, prepare presentation for client, and follow up on pending emails"],
62
+ ],
63
+ theme=gr.themes.Soft()
64
+ )
65
 
66
+ # Add MCP metadata
67
+ organize_goals_into_notion.mcp_type = "tool"
68
+ organize_goals_into_notion.mcp_description = "Organize goals into structured Notion tasks"
69
+ organize_goals_into_notion.mcp_input_type = "string"
70
+ organize_goals_into_notion.mcp_output_type = "json"
71
 
72
+ if __name__ == "__main__":
73
+ demo.queue().launch(
74
+ server_name="0.0.0.0",
75
+ server_port=7860,
76
+ share=False
77
+ )
78
 
79
 
80
 
 
 
llm_parser.py CHANGED
@@ -1,40 +1,72 @@
1
  import anthropic
2
  import os
3
  import json
 
4
  from dotenv import load_dotenv
5
 
6
  load_dotenv() # Load environment variables from .env file
7
 
 
 
 
 
8
  client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
9
 
10
- def llm_parse_tasks(user_input):
 
 
 
 
 
 
 
 
 
11
  prompt = f"""
12
  You are a helpful assistant that turns vague personal goals into clear, actionable tasks.
13
 
14
  Break this input into tasks with:
15
- - task name
16
- - category (Career, Learning, Personal, Outreach, etc.)
17
- - priority (High, Medium, Low)
18
- - optional due date (if mentioned or inferred)
19
- - short notes if relevant
20
 
21
- Return the output as a JSON array of task objects.
 
22
 
23
  Input: \"\"\"{user_input}\"\"\"
24
  """
25
 
26
- response = client.messages.create(
27
- model="claude-3-haiku-20240307",
28
- max_tokens=1024,
29
- temperature=0.4,
30
- messages=[
31
- {"role": "user", "content": prompt}
32
- ]
33
- )
 
 
 
 
34
 
35
- content = response.content[0].text.strip()
 
 
 
 
 
 
 
 
 
 
36
 
37
- try:
38
- return json.loads(content)
 
39
  except json.JSONDecodeError:
40
- return content
 
 
 
1
  import anthropic
2
  import os
3
  import json
4
+ from typing import List, Dict, Union, Any
5
  from dotenv import load_dotenv
6
 
7
  load_dotenv() # Load environment variables from .env file
8
 
9
+ # Check for required environment variables
10
+ if not os.getenv("ANTHROPIC_API_KEY"):
11
+ raise ValueError("ANTHROPIC_API_KEY environment variable is not set")
12
+
13
  client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
14
 
15
+ def llm_parse_tasks(user_input: str) -> Union[List[Dict[str, Any]], str]:
16
+ """
17
+ Parse user input into structured tasks using Claude 3.
18
+
19
+ Args:
20
+ user_input (str): The user's natural language input describing their goals
21
+
22
+ Returns:
23
+ Union[List[Dict[str, Any]], str]: Either a list of task dictionaries or an error message
24
+ """
25
  prompt = f"""
26
  You are a helpful assistant that turns vague personal goals into clear, actionable tasks.
27
 
28
  Break this input into tasks with:
29
+ - task name (key: "task")
30
+ - category (key: "category") - Choose from: Career, Learning, Personal, Outreach, Health, Finance
31
+ - priority (key: "priority") - Choose from: High, Medium, Low
32
+ - optional due date (key: "dueDate") - Use ISO format YYYY-MM-DD if date is mentioned or inferred
33
+ - notes (key: "notes") - Add relevant context or subtasks
34
 
35
+ Return ONLY a valid JSON array of task objects with the exact keys mentioned above.
36
+ Each task MUST have at least task, category, and priority fields.
37
 
38
  Input: \"\"\"{user_input}\"\"\"
39
  """
40
 
41
+ try:
42
+ response = client.messages.create(
43
+ model="claude-3-haiku-20240307",
44
+ max_tokens=1024,
45
+ temperature=0.4,
46
+ messages=[
47
+ {"role": "user", "content": prompt}
48
+ ]
49
+ )
50
+
51
+ content = response.content[0].text.strip()
52
+ tasks = json.loads(content)
53
 
54
+ # Validate required fields
55
+ for task in tasks:
56
+ if not all(k in task for k in ["task", "category", "priority"]):
57
+ return "Error: Each task must have task, category, and priority fields"
58
+
59
+ # Validate category and priority values
60
+ if task["category"] not in ["Career", "Learning", "Personal", "Outreach", "Health", "Finance"]:
61
+ return f"Error: Invalid category '{task['category']}' in task '{task['task']}'"
62
+
63
+ if task["priority"] not in ["High", "Medium", "Low"]:
64
+ return f"Error: Invalid priority '{task['priority']}' in task '{task['task']}'"
65
 
66
+ return tasks
67
+ except anthropic.APIError as e:
68
+ return f"Claude API Error: {str(e)}"
69
  except json.JSONDecodeError:
70
+ return "Error: Failed to parse Claude's response as JSON"
71
+ except Exception as e:
72
+ return f"Unexpected error: {str(e)}"
notion_handler.py CHANGED
@@ -1,50 +1,103 @@
1
  import os
 
2
  from notion_client import Client
3
  from datetime import datetime
4
  from dotenv import load_dotenv
5
 
6
  load_dotenv() # Load environment variables from .env file
7
 
 
 
 
 
 
 
8
  notion = Client(auth=os.getenv("NOTION_TOKEN"))
9
  parent_page_id = os.getenv("NOTION_PARENT_PAGE_ID")
10
 
11
- # Reusable Notion DB schema
12
- def create_tasks_database():
13
- response = notion.databases.create(
14
- parent={"type": "page_id", "page_id": parent_page_id},
15
- title=[{"type": "text", "text": {"content": "NotionTaskSense Tasks"}}],
16
- properties={
17
- "Task": {"title": {}},
18
- "Category": {"select": {"options": []}}, # Options added dynamically
19
- "Priority": {"select": {"options": []}},
20
- "Due Date": {"date": {}},
21
- "Status": {"select": {"options": [{"name": "To Do"}, {"name": "In Progress"}, {"name": "Done"}]}},
22
- "Notes": {"rich_text": {}}
23
- }
24
- )
25
- return response["id"]
26
-
27
- # Add or update tasks into the database
28
- def push_tasks_to_notion(tasks, db_id):
29
- for task in tasks:
30
- properties = {
31
- "Task": {"title": [{"text": {"content": task.get("taskName", "Untitled Task")}}]},
32
- "Category": {"select": {"name": task.get("category", "General")}},
33
- "Priority": {"select": {"name": task.get("priority", "Medium")}},
34
- "Status": {"select": {"name": "To Do"}},
35
- }
36
-
37
- # Optional fields
38
- if "dueDate" in task:
39
- try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  properties["Due Date"] = {"date": {"start": task["dueDate"]}}
41
- except:
42
- pass
43
 
44
- if "notes" in task:
45
- properties["Notes"] = {"rich_text": [{"text": {"content": task["notes"]}}]}
46
 
47
- notion.pages.create(
48
- parent={"database_id": db_id},
49
- properties=properties
50
- )
 
 
 
1
  import os
2
+ from typing import List, Dict, Any
3
  from notion_client import Client
4
  from datetime import datetime
5
  from dotenv import load_dotenv
6
 
7
  load_dotenv() # Load environment variables from .env file
8
 
9
+ # Check for required environment variables
10
+ if not os.getenv("NOTION_TOKEN"):
11
+ raise ValueError("NOTION_TOKEN environment variable is not set")
12
+ if not os.getenv("NOTION_PARENT_PAGE_ID"):
13
+ raise ValueError("NOTION_PARENT_PAGE_ID environment variable is not set")
14
+
15
  notion = Client(auth=os.getenv("NOTION_TOKEN"))
16
  parent_page_id = os.getenv("NOTION_PARENT_PAGE_ID")
17
 
18
+ def create_tasks_database() -> str:
19
+ """
20
+ Create a new Notion database for tasks.
21
+
22
+ Returns:
23
+ str: The ID of the created database
24
+
25
+ Raises:
26
+ Exception: If database creation fails
27
+ """
28
+ try:
29
+ response = notion.databases.create(
30
+ parent={"type": "page_id", "page_id": parent_page_id},
31
+ title=[{"type": "text", "text": {"content": f"NotionTaskSense Tasks - {datetime.now().strftime('%Y-%m-%d')}"}}],
32
+ properties={
33
+ "Task": {"title": {}},
34
+ "Category": {
35
+ "select": {
36
+ "options": [
37
+ {"name": "Career", "color": "blue"},
38
+ {"name": "Learning", "color": "green"},
39
+ {"name": "Personal", "color": "orange"},
40
+ {"name": "Outreach", "color": "purple"},
41
+ {"name": "Health", "color": "red"},
42
+ {"name": "Finance", "color": "yellow"}
43
+ ]
44
+ }
45
+ },
46
+ "Priority": {
47
+ "select": {
48
+ "options": [
49
+ {"name": "High", "color": "red"},
50
+ {"name": "Medium", "color": "yellow"},
51
+ {"name": "Low", "color": "blue"}
52
+ ]
53
+ }
54
+ },
55
+ "Due Date": {"date": {}},
56
+ "Status": {
57
+ "select": {
58
+ "options": [
59
+ {"name": "To Do", "color": "gray"},
60
+ {"name": "In Progress", "color": "blue"},
61
+ {"name": "Done", "color": "green"}
62
+ ]
63
+ }
64
+ },
65
+ "Notes": {"rich_text": {}}
66
+ }
67
+ )
68
+ return response["id"]
69
+ except Exception as e:
70
+ raise Exception(f"Failed to create Notion database: {str(e)}")
71
+
72
+ def push_tasks_to_notion(tasks: List[Dict[str, Any]], db_id: str) -> None:
73
+ """
74
+ Add or update tasks in the Notion database.
75
+
76
+ Args:
77
+ tasks (List[Dict[str, Any]]): List of task dictionaries
78
+ db_id (str): Notion database ID
79
+
80
+ Raises:
81
+ Exception: If pushing tasks fails
82
+ """
83
+ try:
84
+ for task in tasks:
85
+ properties = {
86
+ "Task": {"title": [{"text": {"content": task.get("task", "Untitled Task")}}]},
87
+ "Category": {"select": {"name": task.get("category", "Personal")}},
88
+ "Priority": {"select": {"name": task.get("priority", "Medium")}},
89
+ "Status": {"select": {"name": "To Do"}},
90
+ }
91
+
92
+ if "dueDate" in task and task["dueDate"]:
93
  properties["Due Date"] = {"date": {"start": task["dueDate"]}}
 
 
94
 
95
+ if "notes" in task and task["notes"]:
96
+ properties["Notes"] = {"rich_text": [{"text": {"content": task["notes"]}}]}
97
 
98
+ notion.pages.create(
99
+ parent={"database_id": db_id},
100
+ properties=properties
101
+ )
102
+ except Exception as e:
103
+ raise Exception(f"Failed to push tasks to Notion: {str(e)}")
requirements.txt CHANGED
@@ -7,11 +7,11 @@ charset-normalizer==3.4.2
7
  click==8.2.1
8
  distro==1.9.0
9
  exceptiongroup==1.3.0
10
- fastapi==0.115.12
11
  ffmpy==0.6.0
12
  filelock==3.18.0
13
  fsspec==2025.5.1
14
- gradio==5.33.0
15
  gradio_client==1.10.2
16
  groovy==0.1.2
17
  h11==0.16.0
@@ -25,7 +25,7 @@ jiter==0.10.0
25
  markdown-it-py==3.0.0
26
  MarkupSafe==3.0.2
27
  mdurl==0.1.2
28
- notion-client==2.3.0
29
  numpy==2.2.6
30
  openai==1.85.0
31
  orjson==3.10.18
@@ -37,7 +37,7 @@ pydantic_core==2.33.2
37
  pydub==0.25.1
38
  Pygments==2.19.1
39
  python-dateutil==2.9.0.post0
40
- python-dotenv==1.1.0
41
  python-multipart==0.0.20
42
  pytz==2025.2
43
  PyYAML==6.0.2
@@ -57,5 +57,5 @@ typing-inspection==0.4.1
57
  typing_extensions==4.14.0
58
  tzdata==2025.2
59
  urllib3==2.4.0
60
- uvicorn==0.34.3
61
  websockets==15.0.1
 
7
  click==8.2.1
8
  distro==1.9.0
9
  exceptiongroup==1.3.0
10
+ fastapi>=0.110.0
11
  ffmpy==0.6.0
12
  filelock==3.18.0
13
  fsspec==2025.5.1
14
+ gradio>=4.19.2
15
  gradio_client==1.10.2
16
  groovy==0.1.2
17
  h11==0.16.0
 
25
  markdown-it-py==3.0.0
26
  MarkupSafe==3.0.2
27
  mdurl==0.1.2
28
+ notion-client>=2.2.1
29
  numpy==2.2.6
30
  openai==1.85.0
31
  orjson==3.10.18
 
37
  pydub==0.25.1
38
  Pygments==2.19.1
39
  python-dateutil==2.9.0.post0
40
+ python-dotenv>=1.0.1
41
  python-multipart==0.0.20
42
  pytz==2025.2
43
  PyYAML==6.0.2
 
57
  typing_extensions==4.14.0
58
  tzdata==2025.2
59
  urllib3==2.4.0
60
+ uvicorn>=0.27.1
61
  websockets==15.0.1