BroBro87 commited on
Commit
d62bdc3
·
verified ·
1 Parent(s): 09cb894

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +180 -156
app.py CHANGED
@@ -1,3 +1,6 @@
 
 
 
1
  from composio_llamaindex import ComposioToolSet, App, Action
2
  from llama_index.core.agent import FunctionCallingAgentWorker
3
  from llama_index.core.llms import ChatMessage
@@ -5,195 +8,216 @@ from llama_index.llms.openai import OpenAI
5
  from dotenv import load_dotenv
6
  import gradio as gr
7
  import os
8
- import time
9
- import random
10
 
11
  # Load environment variables
12
  load_dotenv()
13
 
14
- class CalendarWrappedAPI:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def __init__(self):
16
  self.toolset = ComposioToolSet(api_key=os.getenv('COMPOSIO_API_KEY'))
17
  self.llm = OpenAI(model="gpt-4", api_key=os.getenv('OPENAI_API_KEY'))
18
- self.connections = {}
19
 
20
- def initiate_connection(self, entity_id, redirect_url=None):
21
- """Initialize connection using entity_id (username)"""
22
- if redirect_url is None:
23
- redirect_url = "https://yourwebsite.com/connection/success"
24
-
25
  try:
 
 
 
26
  connection_request = self.toolset.initiate_connection(
27
  entity_id=entity_id,
28
  app=App.GOOGLECALENDAR
29
  )
30
 
31
- # Store connection info
32
  self.connections[entity_id] = {
33
- 'status': connection_request.connectionStatus,
34
- 'redirect_url': connection_request.redirectUrl
35
- }
36
-
37
- # Wait for random time between 60-100 seconds
38
- wait_time = random.randint(60, 100)
39
-
40
- # Return redirect URL and wait time immediately
41
- initial_response = {
42
- 'status': 'initiated',
43
  'redirect_url': connection_request.redirectUrl,
44
- 'wait_time': wait_time,
45
- 'message': f'Please click the link below to authenticate. Waiting {wait_time} seconds for completion...'
46
  }
47
 
48
-
49
- # Check final status after waiting
50
- final_status = connection_request.connectionStatus # You would typically check the actual status here
51
- self.connections[entity_id]['status'] = 'active'
52
-
53
- return {
54
- 'status': final_status,
55
- 'redirect_url': connection_request.redirectUrl,
56
- 'message': f'Authentication process completed after {wait_time} seconds. Status: {final_status}'
57
- }
58
 
59
  except Exception as e:
60
- return {
61
- 'status': 'error',
62
- 'message': str(e)
63
- }
64
-
65
- def check_connection_status(self, entity_id):
66
- """Check the connection status using entity_id"""
67
- if entity_id in self.connections:
68
- wait_time = random.randint(60, 100)
69
- return {
70
- 'status': self.connections[entity_id]['status'],
71
- 'wait_time': wait_time,
72
- 'message': f'Status checked after {wait_time} seconds'
73
- }
74
- return {
75
- 'status': 'not_found',
76
- 'message': 'No connection found for this entity ID'
77
- }
78
-
79
- def generate_wrapped(self, entity_id):
80
- """Generate Calendar Wrapped summary using entity_id"""
81
- if entity_id not in self.connections:
82
- return "Please authenticate first by initiating a connection."
83
-
84
- if self.connections[entity_id]['status'] != 'active':
85
- return "Connection not active. Please complete the authentication process."
86
-
87
- tools = self.toolset.get_tools(actions=[Action.GOOGLECALENDAR_GET_CALENDAR,
88
- Action.GOOGLECALENDAR_FIND_EVENT,
89
- Action.GOOGLECALENDAR_GET_CURRENT_DATE_TIME,
90
- Action.GOOGLECALENDAR_LIST_CALENDARS
91
- ])
92
-
93
- prefix_messages = [
94
- ChatMessage(
95
- role="system",
96
- content="""
97
- Use the Get calendar action, find event action from jan 1 to current datetime. Based on the results from these two actions create a Google Calendar Wrapped for the user.
98
- I want the following things: 1. No. of meetings this year, 2. Overall time spent throughout meetings 3. Busiest month 4. Busiest Day 5. Most meetings held with person
99
- 2 more details that you choose.
100
-
101
- Be funny and creative and roast with the inferences drawn from the outputs. Also assign a greek god to the player at the end based on the meetings
102
- """
103
  )
104
- ]
105
-
106
- agent = FunctionCallingAgentWorker(
107
- tools=tools,
108
- llm=self.llm,
109
- prefix_messages=prefix_messages,
110
- max_function_calls=10,
111
- allow_parallel_tool_calls=False,
112
- verbose=True
113
- ).as_agent()
114
-
115
- try:
116
- response = agent.chat(f"Create a Calendar Wrapped summary for user with entity_id: {entity_id}. Find actual data about the user using Google Calendar Actions at your disposal and then generate the wrapped.")
117
- return response
118
- except Exception as e:
119
- return f"Error generating wrapped: {str(e)}"
120
-
121
- def create_gradio_api():
122
- api = CalendarWrappedAPI()
123
-
124
- def handle_connection(entity_id, redirect_url):
125
- result = api.initiate_connection(entity_id, redirect_url)
126
- return (
127
- result['message'],
128
- result['redirect_url'],
129
- result.get('status', 'unknown')
130
- )
131
-
132
- def check_status(entity_id):
133
- result = api.check_connection_status(entity_id)
134
- return f"Status: {result['status']}\n{result['message']}"
135
 
136
- def generate(entity_id):
137
- return api.generate_wrapped(entity_id)
138
-
139
- with gr.Blocks() as demo:
140
- gr.Markdown("""
141
- # Google Calendar Wrapped Generator
142
- Connect your Google Calendar and generate your personalized wrapped summary.
143
- """)
144
-
145
- with gr.Tab("Connection"):
146
- entity_id_input = gr.Textbox(
147
- label="Entity ID (Username)",
148
- placeholder="Enter your username as entity ID"
149
- )
150
- redirect_url_input = gr.Textbox(
151
- label="Redirect URL",
152
- placeholder="https://yourwebsite.com/connection/success"
153
- )
154
- connect_btn = gr.Button("Initialize Connection")
155
 
156
- # New outputs for better visibility
157
- status_message = gr.Textbox(label="Status Message", interactive=False)
158
- redirect_link = gr.HTML(label="Authentication Link")
159
- connection_status = gr.Textbox(label="Connection Status", interactive=False)
160
 
161
- connect_btn.click(
162
- fn=handle_connection,
163
- inputs=[entity_id_input, redirect_url_input],
164
- outputs=[status_message, redirect_link, connection_status]
 
 
165
  )
166
 
167
- with gr.Tab("Status Check"):
168
- status_entity_id = gr.Textbox(
169
- label="Entity ID (Username)",
170
- placeholder="Enter your username as entity ID"
171
  )
172
- check_btn = gr.Button("Check Status")
173
- status_output = gr.Textbox(label="Connection Status")
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
- check_btn.click(
176
- fn=check_status,
177
- inputs=status_entity_id,
178
- outputs=status_output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  )
180
 
181
- with gr.Tab("Generate Wrapped"):
182
- wrapped_entity_id = gr.Textbox(
183
- label="Entity ID (Username)",
184
- placeholder="Enter your username as entity ID"
 
185
  )
186
- generate_btn = gr.Button("Generate Wrapped")
187
- wrapped_output = gr.Textbox(label="Wrapped Summary", lines=10)
188
 
189
- generate_btn.click(
190
- fn=generate,
191
- inputs=wrapped_entity_id,
192
- outputs=wrapped_output
193
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
- return demo
196
 
197
  if __name__ == "__main__":
198
- demo = create_gradio_api()
199
- demo.launch(share=True) # Set share=False in production
 
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+ from typing import Optional, Dict, Any
4
  from composio_llamaindex import ComposioToolSet, App, Action
5
  from llama_index.core.agent import FunctionCallingAgentWorker
6
  from llama_index.core.llms import ChatMessage
 
8
  from dotenv import load_dotenv
9
  import gradio as gr
10
  import os
11
+ import json
12
+ from datetime import datetime
13
 
14
  # Load environment variables
15
  load_dotenv()
16
 
17
+ class ConnectionStatus(Enum):
18
+ PENDING = "pending"
19
+ ACTIVE = "active"
20
+ FAILED = "failed"
21
+ NOT_FOUND = "not_found"
22
+
23
+ @dataclass
24
+ class APIResponse:
25
+ success: bool
26
+ data: Optional[Dict[str, Any]] = None
27
+ error: Optional[str] = None
28
+
29
+ def to_json(self) -> str:
30
+ return json.dumps({
31
+ "success": self.success,
32
+ "data": self.data,
33
+ "error": self.error
34
+ })
35
+
36
+ class CalendarService:
37
  def __init__(self):
38
  self.toolset = ComposioToolSet(api_key=os.getenv('COMPOSIO_API_KEY'))
39
  self.llm = OpenAI(model="gpt-4", api_key=os.getenv('OPENAI_API_KEY'))
40
+ self.connections: Dict[str, Dict[str, Any]] = {}
41
 
42
+ def initiate_connection(self, entity_id: str, redirect_url: Optional[str] = None) -> APIResponse:
 
 
 
 
43
  try:
44
+ if not redirect_url:
45
+ redirect_url = "https://yourwebsite.com/connection/success"
46
+
47
  connection_request = self.toolset.initiate_connection(
48
  entity_id=entity_id,
49
  app=App.GOOGLECALENDAR
50
  )
51
 
 
52
  self.connections[entity_id] = {
53
+ 'status': ConnectionStatus.PENDING.value,
 
 
 
 
 
 
 
 
 
54
  'redirect_url': connection_request.redirectUrl,
55
+ 'created_at': datetime.now().isoformat()
 
56
  }
57
 
58
+ return APIResponse(
59
+ success=True,
60
+ data={
61
+ 'status': ConnectionStatus.PENDING.value,
62
+ 'redirect_url': connection_request.redirectUrl,
63
+ 'wait_time': 60,
64
+ 'message': "Please authenticate using the provided link."
65
+ }
66
+ )
 
67
 
68
  except Exception as e:
69
+ return APIResponse(
70
+ success=False,
71
+ error=f"Failed to initiate connection: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
+ def check_status(self, entity_id: str) -> APIResponse:
75
+ try:
76
+ if entity_id not in self.connections:
77
+ return APIResponse(
78
+ success=False,
79
+ error="No connection found for this entity ID"
80
+ )
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
+ # In a real implementation, you would check the actual status
83
+ # For now, we'll simulate the status check
84
+ connection = self.connections[entity_id]
 
85
 
86
+ return APIResponse(
87
+ success=True,
88
+ data={
89
+ 'status': connection['status'],
90
+ 'message': f"Connection status: {connection['status']}"
91
+ }
92
  )
93
 
94
+ except Exception as e:
95
+ return APIResponse(
96
+ success=False,
97
+ error=f"Failed to check status: {str(e)}"
98
  )
99
+
100
+ def generate_wrapped(self, entity_id: str) -> APIResponse:
101
+ try:
102
+ if entity_id not in self.connections:
103
+ return APIResponse(
104
+ success=False,
105
+ error="Please authenticate first by initiating a connection."
106
+ )
107
+
108
+ if self.connections[entity_id]['status'] != ConnectionStatus.ACTIVE.value:
109
+ return APIResponse(
110
+ success=False,
111
+ error="Connection not active. Please complete the authentication process."
112
+ )
113
 
114
+ tools = self.toolset.get_tools([
115
+ Action.GOOGLECALENDAR_GET_CALENDAR,
116
+ Action.GOOGLECALENDAR_FIND_EVENT,
117
+ Action.GOOGLECALENDAR_GET_CURRENT_DATE_TIME,
118
+ Action.GOOGLECALENDAR_LIST_CALENDARS
119
+ ])
120
+
121
+ agent = FunctionCallingAgentWorker(
122
+ tools=tools,
123
+ llm=self.llm,
124
+ prefix_messages=[
125
+ ChatMessage(
126
+ role="system",
127
+ content="""
128
+ Generate a creative Google Calendar Wrapped summary including:
129
+ 1. Total meetings this year
130
+ 2. Overall time spent in meetings
131
+ 3. Busiest month
132
+ 4. Busiest day
133
+ 5. Most frequent meeting participant
134
+ 6. Average meeting duration
135
+ 7. Most common meeting time
136
+
137
+ Be entertaining and witty with the analysis. Conclude by assigning
138
+ a Greek god persona based on their meeting patterns.
139
+ """
140
+ )
141
+ ],
142
+ max_function_calls=10,
143
+ allow_parallel_tool_calls=False,
144
+ verbose=True
145
+ ).as_agent()
146
+
147
+ response = agent.chat(
148
+ f"Create a Calendar Wrapped summary for user with entity_id: {entity_id}. "
149
+ "Use the available Google Calendar actions to gather real data about the user's calendar usage."
150
  )
151
 
152
+ return APIResponse(
153
+ success=True,
154
+ data={
155
+ 'wrapped_summary': str(response)
156
+ }
157
  )
 
 
158
 
159
+ except Exception as e:
160
+ return APIResponse(
161
+ success=False,
162
+ error=f"Failed to generate wrapped: {str(e)}"
163
  )
164
+
165
+ def create_gradio_api():
166
+ service = CalendarService()
167
+
168
+ def handle_connection(entity_id: str, redirect_url: Optional[str] = None) -> str:
169
+ response = service.initiate_connection(entity_id, redirect_url)
170
+ return response.to_json()
171
+
172
+ def check_status(entity_id: str) -> str:
173
+ response = service.check_status(entity_id)
174
+ return response.to_json()
175
+
176
+ def generate_wrapped(entity_id: str) -> str:
177
+ response = service.generate_wrapped(entity_id)
178
+ return response.to_json()
179
+
180
+ # Create API endpoints
181
+ connection_api = gr.Interface(
182
+ fn=handle_connection,
183
+ inputs=[
184
+ gr.Textbox(label="Entity ID"),
185
+ gr.Textbox(label="Redirect URL", placeholder="https://yourwebsite.com/connection/success")
186
+ ],
187
+ outputs=gr.JSON(),
188
+ title="Initialize Calendar Connection",
189
+ description="Start a new calendar connection for an entity",
190
+ examples=[["user123", "https://example.com/callback"]]
191
+ )
192
+
193
+ status_api = gr.Interface(
194
+ fn=check_status,
195
+ inputs=gr.Textbox(label="Entity ID"),
196
+ outputs=gr.JSON(),
197
+ title="Check Connection Status",
198
+ description="Check the status of an existing connection",
199
+ examples=[["user123"]]
200
+ )
201
+
202
+ wrapped_api = gr.Interface(
203
+ fn=generate_wrapped,
204
+ inputs=gr.Textbox(label="Entity ID"),
205
+ outputs=gr.JSON(),
206
+ title="Generate Calendar Wrapped",
207
+ description="Generate a calendar wrapped summary for an entity",
208
+ examples=[["user123"]]
209
+ )
210
+
211
+ # Combine all interfaces
212
+ api = gr.TabbedInterface(
213
+ [connection_api, status_api, wrapped_api],
214
+ ["Connect", "Check Status", "Generate Wrapped"],
215
+ title="Calendar Wrapped API",
216
+ description="API endpoints for Calendar Wrapped functionality"
217
+ )
218
 
219
+ return api
220
 
221
  if __name__ == "__main__":
222
+ api = create_gradio_api()
223
+ api.launch(server_name="0.0.0.0", server_port=7860)