OpelSpeedster commited on
Commit
5cac522
·
verified ·
1 Parent(s): 77c71fd

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +11 -16
  2. app.py +174 -69
  3. calendar_memory.json +23 -0
  4. memory.py +68 -0
README.md CHANGED
@@ -1,16 +1,11 @@
1
- ---
2
- title: Calender Memory
3
- emoji: 💬
4
- colorFrom: yellow
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 6.5.1
8
- app_file: app.py
9
- pinned: false
10
- hf_oauth: true
11
- hf_oauth_scopes:
12
- - inference-api
13
- short_description: A calender agent which remember your claender dates (by reg)
14
- ---
15
-
16
- An example chatbot using [Gradio](https://gradio.app), [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/v0.22.2/en/index), and the [Hugging Face Inference API](https://huggingface.co/docs/api-inference/index).
 
1
+ ---
2
+ title: Calendar Memory Agent
3
+ sdk: gradio
4
+ sdk_version: 6.16.0
5
+ app_file: app.py
6
+ pinned: false
7
+ ---
8
+
9
+ # Calendar Memory Agent
10
+
11
+ An AI agent powered by Grok that remembers your calendar events, deadlines, and important dates across conversations.
 
 
 
 
 
app.py CHANGED
@@ -1,69 +1,174 @@
1
- import gradio as gr
2
- from huggingface_hub import InferenceClient
3
-
4
-
5
- def respond(
6
- message,
7
- history: list[dict[str, str]],
8
- system_message,
9
- max_tokens,
10
- temperature,
11
- top_p,
12
- hf_token: gr.OAuthToken,
13
- ):
14
- """
15
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
16
- """
17
- client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b")
18
-
19
- messages = [{"role": "system", "content": system_message}]
20
-
21
- messages.extend(history)
22
-
23
- messages.append({"role": "user", "content": message})
24
-
25
- response = ""
26
-
27
- for message in client.chat_completion(
28
- messages,
29
- max_tokens=max_tokens,
30
- stream=True,
31
- temperature=temperature,
32
- top_p=top_p,
33
- ):
34
- choices = message.choices
35
- token = ""
36
- if len(choices) and choices[0].delta.content:
37
- token = choices[0].delta.content
38
-
39
- response += token
40
- yield response
41
-
42
-
43
- """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- chatbot = gr.ChatInterface(
47
- respond,
48
- additional_inputs=[
49
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
50
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
51
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
52
- gr.Slider(
53
- minimum=0.1,
54
- maximum=1.0,
55
- value=0.95,
56
- step=0.05,
57
- label="Top-p (nucleus sampling)",
58
- ),
59
- ],
60
- )
61
-
62
- with gr.Blocks() as demo:
63
- with gr.Sidebar():
64
- gr.LoginButton()
65
- chatbot.render()
66
-
67
-
68
- if __name__ == "__main__":
69
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+
4
+ import gradio as gr
5
+ from groq import Groq
6
+
7
+ from memory import add_event, search_events, get_upcoming_events
8
+
9
+
10
+ def build_system_prompt():
11
+ """Assemble the system prompt with upcoming events context."""
12
+ upcoming = get_upcoming_events(days=7)
13
+
14
+ base_prompt = (
15
+ "You are a helpful calendar memory agent. You remember the user's "
16
+ "important dates, deadlines, meetings, and events. You can save new "
17
+ "events and retrieve existing ones.\n\n"
18
+ "When the user mentions a date, deadline, or event, use the save_event "
19
+ "tool to store it. When they ask about their schedule, use the "
20
+ "get_events tool to look it up.\n\n"
21
+ "Always confirm what you saved or found. Be concise and helpful."
22
+ )
23
+
24
+ if upcoming:
25
+ events_text = "\n".join(
26
+ f"- {e['date']}: {e['description']} ({e['category']})"
27
+ for e in upcoming
28
+ )
29
+ base_prompt += (
30
+ f"\n\nUpcoming events (next 7 days):\n{events_text}"
31
+ )
32
+ else:
33
+ base_prompt += "\n\nNo upcoming events in the next 7 days."
34
+
35
+ return base_prompt
36
+
37
+ def define_tools():
38
+ """Define the tools available to the model."""
39
+ tools = [
40
+ {
41
+ "type": "function",
42
+ "function": {
43
+ "name": "save_event",
44
+ "description": "Save a new calendar event, deadline, or reminder to memory.",
45
+ "parameters": {
46
+ "type": "object",
47
+ "properties": {
48
+ "date": {
49
+ "type": "string",
50
+ "description": "The date of the event in YYYY-MM-DD format"
51
+ },
52
+ "description": {
53
+ "type": "string",
54
+ "description": "A brief description of the event"
55
+ },
56
+ "category": {
57
+ "type": "string",
58
+ "enum": ["deadline", "meeting", "reminder", "event"],
59
+ "description": "The category of the event"
60
+ }
61
+ },
62
+ "required": ["date", "description"]
63
+ }
64
+ }
65
+ },
66
+ {
67
+ "type": "function",
68
+ "function": {
69
+ "name": "get_events",
70
+ "description": "Retrieve calendar events from memory by date range or keyword.",
71
+ "parameters": {
72
+ "type": "object",
73
+ "properties": {
74
+ "start_date": {
75
+ "type": "string",
76
+ "description": "Start date in YYYY-MM-DD format (optional)"
77
+ },
78
+ "end_date": {
79
+ "type": "string",
80
+ "description": "End date in YYYY-MM-DD format (optional)"
81
+ },
82
+ "keyword": {
83
+ "type": "string",
84
+ "description": "Keyword to search in event descriptions (optional)"
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ ]
91
+ return tools
92
+
93
+ def handle_tool_call(tool_call):
94
+ """Execute a client-side tool call and return the result."""
95
+ name = tool_call.function.name
96
+ args = json.loads(tool_call.function.arguments)
97
+
98
+ if name == "save_event":
99
+ event = add_event(
100
+ date=args["date"],
101
+ description=args["description"],
102
+ category=args.get("category", "event")
103
+ )
104
+ return json.dumps({
105
+ "status": "saved",
106
+ "event": event
107
+ })
108
+
109
+ elif name == "get_events":
110
+ events = search_events(
111
+ start_date=args.get("start_date"),
112
+ end_date=args.get("end_date"),
113
+ keyword=args.get("keyword")
114
+ )
115
+ return json.dumps({
116
+ "status": "found",
117
+ "count": len(events),
118
+ "events": events
119
+ })
120
+
121
+ return json.dumps({"error": f"Unknown tool: {name}"})
122
+
123
+ def chat_with_agent(message, history):
124
+ """Process a user message through the Groq agent with tool calling."""
125
+ client = Groq(api_key=os.getenv("GROQ_API_KEY"))
126
+ tools = define_tools()
127
+ system_prompt = build_system_prompt()
128
+
129
+ # Build the messages array with system prompt and user message
130
+ messages = [
131
+ {"role": "system", "content": system_prompt},
132
+ {"role": "user", "content": message}
133
+ ]
134
+
135
+ while True:
136
+ response = client.chat.completions.create(
137
+ model="llama-3.3-70b-versatile",
138
+ messages=messages,
139
+ tools=tools,
140
+ )
141
+
142
+ choice = response.choices[0]
143
+
144
+ # If the model wants to call tools, execute them
145
+ if choice.finish_reason == "tool_calls":
146
+ # Append the assistant's message (with tool_calls) to history
147
+ messages.append(choice.message)
148
+
149
+ # Execute each tool call and append results
150
+ for tc in choice.message.tool_calls:
151
+ result = handle_tool_call(tc)
152
+ messages.append({
153
+ "role": "tool",
154
+ "tool_call_id": tc.id,
155
+ "name": tc.function.name,
156
+ "content": result,
157
+ })
158
+ else:
159
+ # No tool calls — return the final text response
160
+ return choice.message.content
161
+
162
+ demo = gr.ChatInterface(
163
+ fn=chat_with_agent,
164
+ title="Calendar Memory Agent",
165
+ description="I remember your dates, deadlines, and events. Tell me about upcoming events or ask what's on your schedule!",
166
+ examples=[
167
+ "I have a dentist appointment on 2026-06-15",
168
+ "What events do I have coming up?",
169
+ "My project deadline is 2026-06-20",
170
+ ],
171
+ )
172
+
173
+ if __name__ == "__main__":
174
+ demo.launch()
calendar_memory.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "id": "28320f10-b3b2-4fc6-aa1b-5aa7a06d63b4",
4
+ "date": "2026-06-15",
5
+ "description": "Dentist appointment",
6
+ "category": "reminder",
7
+ "created_at": "2026-06-05T00:35:17.226991"
8
+ },
9
+ {
10
+ "id": "9cb9ae90-eaea-455b-820c-8808da994a8e",
11
+ "date": "2026-06-15",
12
+ "description": "Dentist appointment",
13
+ "category": "reminder",
14
+ "created_at": "2026-06-05T09:29:36.731507"
15
+ },
16
+ {
17
+ "id": "8f7f4239-639b-43c1-a0cf-744904631007",
18
+ "date": "2026-06-15",
19
+ "description": "dentist appointment",
20
+ "category": "meeting",
21
+ "created_at": "2026-06-05T09:32:58.742139"
22
+ }
23
+ ]
memory.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import uuid
4
+ from datetime import datetime, timedelta
5
+
6
+
7
+ MEMORY_FILE = "calendar_memory.json"
8
+
9
+
10
+ def load_events():
11
+ """Load all events from the JSON memory file."""
12
+ if not os.path.exists(MEMORY_FILE):
13
+ return []
14
+ with open(MEMORY_FILE, "r") as f:
15
+ return json.load(f)
16
+
17
+
18
+ def save_events(events):
19
+ """Save all events to the JSON memory file."""
20
+ with open(MEMORY_FILE, "w") as f:
21
+ json.dump(events, f, indent=2)
22
+
23
+ def add_event(date, description, category="event"):
24
+ """Add a new calendar event to memory."""
25
+ events = load_events()
26
+ new_event = {
27
+ "id": str(uuid.uuid4()),
28
+ "date": date,
29
+ "description": description,
30
+ "category": category,
31
+ "created_at": datetime.now().isoformat()
32
+ }
33
+ events.append(new_event)
34
+ save_events(events)
35
+ return new_event
36
+
37
+ def search_events(start_date=None, end_date=None, keyword=None):
38
+ """Search events by date range and/or keyword."""
39
+ events = load_events()
40
+ results = []
41
+
42
+ for event in events:
43
+ match = True
44
+
45
+ if start_date:
46
+ if event["date"] < start_date:
47
+ match = False
48
+
49
+ if end_date:
50
+ if event["date"] > end_date:
51
+ match = False
52
+
53
+ if keyword:
54
+ if keyword.lower() not in event["description"].lower():
55
+ match = False
56
+
57
+ if match:
58
+ results.append(event)
59
+
60
+ results.sort(key=lambda e: e["date"])
61
+ return results
62
+
63
+ def get_upcoming_events(days=7):
64
+ """Get events in the next N days for context assembly."""
65
+ today = datetime.now().strftime("%Y-%m-%d")
66
+ end = (datetime.now() + timedelta(days=days)).strftime("%Y-%m-%d")
67
+ return search_events(start_date=today, end_date=end)
68
+