universal-mcp-applications 0.1.30rc2__py3-none-any.whl → 0.1.36rc2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- universal_mcp/applications/ahrefs/app.py +52 -198
- universal_mcp/applications/airtable/app.py +23 -122
- universal_mcp/applications/apollo/app.py +111 -464
- universal_mcp/applications/asana/app.py +417 -1567
- universal_mcp/applications/aws_s3/app.py +36 -103
- universal_mcp/applications/bill/app.py +546 -1957
- universal_mcp/applications/box/app.py +1068 -3981
- universal_mcp/applications/braze/app.py +364 -1430
- universal_mcp/applications/browser_use/app.py +2 -8
- universal_mcp/applications/cal_com_v2/app.py +207 -625
- universal_mcp/applications/calendly/app.py +61 -200
- universal_mcp/applications/canva/app.py +45 -110
- universal_mcp/applications/clickup/app.py +207 -674
- universal_mcp/applications/coda/app.py +146 -426
- universal_mcp/applications/confluence/app.py +310 -1098
- universal_mcp/applications/contentful/app.py +36 -151
- universal_mcp/applications/crustdata/app.py +28 -107
- universal_mcp/applications/dialpad/app.py +283 -756
- universal_mcp/applications/digitalocean/app.py +1766 -5777
- universal_mcp/applications/domain_checker/app.py +3 -54
- universal_mcp/applications/e2b/app.py +14 -64
- universal_mcp/applications/elevenlabs/app.py +9 -47
- universal_mcp/applications/exa/app.py +6 -17
- universal_mcp/applications/falai/app.py +24 -101
- universal_mcp/applications/figma/app.py +53 -137
- universal_mcp/applications/file_system/app.py +2 -13
- universal_mcp/applications/firecrawl/app.py +51 -152
- universal_mcp/applications/fireflies/app.py +59 -281
- universal_mcp/applications/fpl/app.py +91 -528
- universal_mcp/applications/fpl/utils/fixtures.py +15 -49
- universal_mcp/applications/fpl/utils/helper.py +25 -89
- universal_mcp/applications/fpl/utils/league_utils.py +20 -64
- universal_mcp/applications/ghost_content/app.py +52 -161
- universal_mcp/applications/github/app.py +19 -56
- universal_mcp/applications/gong/app.py +88 -248
- universal_mcp/applications/google_calendar/app.py +16 -68
- universal_mcp/applications/google_docs/app.py +88 -188
- universal_mcp/applications/google_drive/app.py +141 -463
- universal_mcp/applications/google_gemini/app.py +12 -64
- universal_mcp/applications/google_mail/app.py +28 -157
- universal_mcp/applications/google_searchconsole/app.py +15 -48
- universal_mcp/applications/google_sheet/app.py +103 -580
- universal_mcp/applications/google_sheet/helper.py +10 -37
- universal_mcp/applications/hashnode/app.py +57 -269
- universal_mcp/applications/heygen/app.py +44 -122
- universal_mcp/applications/http_tools/app.py +10 -32
- universal_mcp/applications/hubspot/api_segments/crm_api.py +460 -1573
- universal_mcp/applications/hubspot/api_segments/marketing_api.py +74 -262
- universal_mcp/applications/hubspot/app.py +23 -87
- universal_mcp/applications/jira/app.py +2071 -7986
- universal_mcp/applications/klaviyo/app.py +494 -1376
- universal_mcp/applications/linkedin/README.md +9 -2
- universal_mcp/applications/linkedin/app.py +392 -212
- universal_mcp/applications/mailchimp/app.py +450 -1605
- universal_mcp/applications/markitdown/app.py +8 -20
- universal_mcp/applications/miro/app.py +217 -699
- universal_mcp/applications/ms_teams/app.py +64 -186
- universal_mcp/applications/neon/app.py +86 -192
- universal_mcp/applications/notion/app.py +21 -36
- universal_mcp/applications/onedrive/app.py +16 -38
- universal_mcp/applications/openai/app.py +42 -165
- universal_mcp/applications/outlook/app.py +24 -84
- universal_mcp/applications/perplexity/app.py +4 -19
- universal_mcp/applications/pipedrive/app.py +832 -3142
- universal_mcp/applications/posthog/app.py +163 -432
- universal_mcp/applications/reddit/app.py +40 -139
- universal_mcp/applications/resend/app.py +41 -107
- universal_mcp/applications/retell/app.py +14 -41
- universal_mcp/applications/rocketlane/app.py +221 -934
- universal_mcp/applications/scraper/README.md +7 -4
- universal_mcp/applications/scraper/app.py +216 -102
- universal_mcp/applications/semanticscholar/app.py +22 -64
- universal_mcp/applications/semrush/app.py +43 -77
- universal_mcp/applications/sendgrid/app.py +512 -1262
- universal_mcp/applications/sentry/app.py +271 -906
- universal_mcp/applications/serpapi/app.py +40 -143
- universal_mcp/applications/sharepoint/app.py +17 -39
- universal_mcp/applications/shopify/app.py +1551 -4287
- universal_mcp/applications/shortcut/app.py +155 -417
- universal_mcp/applications/slack/app.py +50 -101
- universal_mcp/applications/spotify/app.py +126 -325
- universal_mcp/applications/supabase/app.py +104 -213
- universal_mcp/applications/tavily/app.py +1 -1
- universal_mcp/applications/trello/app.py +693 -2656
- universal_mcp/applications/twilio/app.py +14 -50
- universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
- universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
- universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
- universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
- universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
- universal_mcp/applications/whatsapp/app.py +35 -186
- universal_mcp/applications/whatsapp/audio.py +2 -6
- universal_mcp/applications/whatsapp/whatsapp.py +17 -51
- universal_mcp/applications/whatsapp_business/app.py +70 -283
- universal_mcp/applications/wrike/app.py +45 -118
- universal_mcp/applications/yahoo_finance/app.py +19 -65
- universal_mcp/applications/youtube/app.py +75 -261
- universal_mcp/applications/zenquotes/app.py +2 -2
- {universal_mcp_applications-0.1.30rc2.dist-info → universal_mcp_applications-0.1.36rc2.dist-info}/METADATA +2 -2
- {universal_mcp_applications-0.1.30rc2.dist-info → universal_mcp_applications-0.1.36rc2.dist-info}/RECORD +105 -105
- {universal_mcp_applications-0.1.30rc2.dist-info → universal_mcp_applications-0.1.36rc2.dist-info}/WHEEL +0 -0
- {universal_mcp_applications-0.1.30rc2.dist-info → universal_mcp_applications-0.1.36rc2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,49 +1,21 @@
|
|
|
1
1
|
from typing import Any
|
|
2
|
-
|
|
3
2
|
import requests
|
|
4
3
|
from universal_mcp.agentr.integration import AgentrIntegration
|
|
5
4
|
from universal_mcp.applications.application import BaseApplication
|
|
6
5
|
from universal_mcp.exceptions import NotAuthorizedError
|
|
7
|
-
|
|
8
|
-
from universal_mcp.applications.whatsapp.whatsapp import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
from universal_mcp.applications.whatsapp.whatsapp import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
from universal_mcp.applications.whatsapp.whatsapp import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
from universal_mcp.applications.whatsapp.whatsapp import
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
21
|
-
get_direct_chat_by_contact as whatsapp_get_direct_chat_by_contact,
|
|
22
|
-
)
|
|
23
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
24
|
-
get_last_interaction as whatsapp_get_last_interaction,
|
|
25
|
-
)
|
|
26
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
27
|
-
get_message_context as whatsapp_get_message_context,
|
|
28
|
-
)
|
|
29
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
30
|
-
list_chats as whatsapp_list_chats,
|
|
31
|
-
)
|
|
32
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
33
|
-
list_messages as whatsapp_list_messages,
|
|
34
|
-
)
|
|
35
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
36
|
-
search_contacts as whatsapp_search_contacts,
|
|
37
|
-
)
|
|
38
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
39
|
-
send_audio_message as whatsapp_audio_voice_message,
|
|
40
|
-
)
|
|
41
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
42
|
-
send_file as whatsapp_send_file,
|
|
43
|
-
)
|
|
44
|
-
from universal_mcp.applications.whatsapp.whatsapp import (
|
|
45
|
-
send_message as whatsapp_send_message,
|
|
46
|
-
)
|
|
6
|
+
from universal_mcp.applications.whatsapp.whatsapp import WHATSAPP_API_BASE_URL
|
|
7
|
+
from universal_mcp.applications.whatsapp.whatsapp import download_media as whatsapp_download_media
|
|
8
|
+
from universal_mcp.applications.whatsapp.whatsapp import get_chat as whatsapp_get_chat
|
|
9
|
+
from universal_mcp.applications.whatsapp.whatsapp import get_contact_chats as whatsapp_get_contact_chats
|
|
10
|
+
from universal_mcp.applications.whatsapp.whatsapp import get_direct_chat_by_contact as whatsapp_get_direct_chat_by_contact
|
|
11
|
+
from universal_mcp.applications.whatsapp.whatsapp import get_last_interaction as whatsapp_get_last_interaction
|
|
12
|
+
from universal_mcp.applications.whatsapp.whatsapp import get_message_context as whatsapp_get_message_context
|
|
13
|
+
from universal_mcp.applications.whatsapp.whatsapp import list_chats as whatsapp_list_chats
|
|
14
|
+
from universal_mcp.applications.whatsapp.whatsapp import list_messages as whatsapp_list_messages
|
|
15
|
+
from universal_mcp.applications.whatsapp.whatsapp import search_contacts as whatsapp_search_contacts
|
|
16
|
+
from universal_mcp.applications.whatsapp.whatsapp import send_audio_message as whatsapp_audio_voice_message
|
|
17
|
+
from universal_mcp.applications.whatsapp.whatsapp import send_file as whatsapp_send_file
|
|
18
|
+
from universal_mcp.applications.whatsapp.whatsapp import send_message as whatsapp_send_message
|
|
47
19
|
|
|
48
20
|
|
|
49
21
|
class WhatsappApp(BaseApplication):
|
|
@@ -63,7 +35,6 @@ class WhatsappApp(BaseApplication):
|
|
|
63
35
|
"""
|
|
64
36
|
if not self.integration:
|
|
65
37
|
raise ValueError("No integration available to get API key from")
|
|
66
|
-
|
|
67
38
|
try:
|
|
68
39
|
headers = self.integration.client.client.headers
|
|
69
40
|
api_key = headers.get("X-API-KEY")
|
|
@@ -89,19 +60,13 @@ class WhatsappApp(BaseApplication):
|
|
|
89
60
|
Triggers WhatsApp authentication flow when no integration is available.
|
|
90
61
|
Raises NotAuthorizedError with authorization URL when authentication is needed.
|
|
91
62
|
"""
|
|
92
|
-
|
|
93
|
-
# Try WhatsApp authentication
|
|
94
63
|
auth_result = self._authenticate_whatsapp()
|
|
95
64
|
if auth_result[0] is True:
|
|
96
65
|
return True
|
|
97
66
|
elif isinstance(auth_result[1], str):
|
|
98
|
-
# auth_result contains the authorization URL message
|
|
99
67
|
raise NotAuthorizedError(auth_result[1])
|
|
100
68
|
else:
|
|
101
|
-
|
|
102
|
-
raise NotAuthorizedError(
|
|
103
|
-
"WhatsApp authentication failed. Please check your configuration."
|
|
104
|
-
)
|
|
69
|
+
raise NotAuthorizedError("WhatsApp authentication failed. Please check your configuration.")
|
|
105
70
|
|
|
106
71
|
def _authenticate_whatsapp(self) -> tuple[bool, str]:
|
|
107
72
|
"""
|
|
@@ -109,20 +74,11 @@ class WhatsappApp(BaseApplication):
|
|
|
109
74
|
Makes a POST request to the auth endpoint.
|
|
110
75
|
"""
|
|
111
76
|
try:
|
|
112
|
-
# Use the API key from the integration
|
|
113
77
|
user_id = self.api_key
|
|
114
78
|
if not user_id:
|
|
115
79
|
raise ValueError("No API key available from integration")
|
|
116
|
-
|
|
117
80
|
auth_url = f"{self.base_url}/api/auth"
|
|
118
|
-
|
|
119
|
-
response = requests.post(
|
|
120
|
-
auth_url,
|
|
121
|
-
headers={"Content-Type": "application/json"},
|
|
122
|
-
json={"user_id": user_id},
|
|
123
|
-
timeout=60,
|
|
124
|
-
)
|
|
125
|
-
|
|
81
|
+
response = requests.post(auth_url, headers={"Content-Type": "application/json"}, json={"user_id": user_id}, timeout=60)
|
|
126
82
|
if response.status_code == 200:
|
|
127
83
|
result = response.json()
|
|
128
84
|
if result.get("status") == "qr_required":
|
|
@@ -134,15 +90,12 @@ class WhatsappApp(BaseApplication):
|
|
|
134
90
|
elif result.get("status") == "connected":
|
|
135
91
|
return (True, "User already authenticated")
|
|
136
92
|
else:
|
|
137
|
-
# Return QR URL even when auth fails, so user can try to authenticate
|
|
138
93
|
qr_url = f"{self.base_url}/api/qr?user_id={user_id}"
|
|
139
94
|
return (
|
|
140
95
|
False,
|
|
141
96
|
f"Please ask the user to visit the following url to authorize WhatsApp: {qr_url}. Render the url in proper markdown format with a clickable link.",
|
|
142
97
|
)
|
|
143
|
-
|
|
144
98
|
except Exception:
|
|
145
|
-
# Return QR URL when there's an exception, so user can try to authenticate
|
|
146
99
|
user_id = self.api_key
|
|
147
100
|
if user_id:
|
|
148
101
|
qr_url = f"{self.base_url}/api/qr?user_id={user_id}"
|
|
@@ -153,10 +106,7 @@ class WhatsappApp(BaseApplication):
|
|
|
153
106
|
else:
|
|
154
107
|
return (False, "No API key available from integration")
|
|
155
108
|
|
|
156
|
-
def search_contacts(
|
|
157
|
-
self,
|
|
158
|
-
query: str,
|
|
159
|
-
) -> list[dict[str, Any]]:
|
|
109
|
+
async def search_contacts(self, query: str) -> list[dict[str, Any]]:
|
|
160
110
|
"""
|
|
161
111
|
Searches for WhatsApp contacts by name or phone number. This function takes a query string, handles user authentication, and calls the underlying API to find and return a list of matching contacts. It serves as the primary method to look up contact information within the application.
|
|
162
112
|
|
|
@@ -174,15 +124,12 @@ class WhatsappApp(BaseApplication):
|
|
|
174
124
|
"""
|
|
175
125
|
if query is None:
|
|
176
126
|
raise ValueError("Missing required parameter 'query'.")
|
|
177
|
-
|
|
178
|
-
# Trigger authentication
|
|
179
127
|
self._authenticator()
|
|
180
|
-
|
|
181
128
|
user_id = self.api_key
|
|
182
129
|
contacts = whatsapp_search_contacts(query, user_id)
|
|
183
130
|
return contacts
|
|
184
131
|
|
|
185
|
-
def search_messages(
|
|
132
|
+
async def search_messages(
|
|
186
133
|
self,
|
|
187
134
|
after: str | None = None,
|
|
188
135
|
before: str | None = None,
|
|
@@ -219,9 +166,7 @@ class WhatsappApp(BaseApplication):
|
|
|
219
166
|
Tags:
|
|
220
167
|
whatsapp.messages, important
|
|
221
168
|
"""
|
|
222
|
-
# Trigger authentication
|
|
223
169
|
self._authenticator()
|
|
224
|
-
|
|
225
170
|
user_id = self.api_key
|
|
226
171
|
messages = whatsapp_list_messages(
|
|
227
172
|
after=after,
|
|
@@ -238,13 +183,8 @@ class WhatsappApp(BaseApplication):
|
|
|
238
183
|
)
|
|
239
184
|
return messages
|
|
240
185
|
|
|
241
|
-
def search_chats(
|
|
242
|
-
self,
|
|
243
|
-
query: str | None = None,
|
|
244
|
-
limit: int = 20,
|
|
245
|
-
page: int = 0,
|
|
246
|
-
include_last_message: bool = True,
|
|
247
|
-
sort_by: str = "last_active",
|
|
186
|
+
async def search_chats(
|
|
187
|
+
self, query: str | None = None, limit: int = 20, page: int = 0, include_last_message: bool = True, sort_by: str = "last_active"
|
|
248
188
|
) -> list[dict[str, Any]]:
|
|
249
189
|
"""
|
|
250
190
|
Retrieves a paginated list of WhatsApp chats, allowing filtering by a search query and sorting by activity or name. Unlike `get_chat`, which fetches a single known chat, this function provides broad search and discovery capabilities across multiple user conversations.
|
|
@@ -265,25 +205,14 @@ class WhatsappApp(BaseApplication):
|
|
|
265
205
|
Tags:
|
|
266
206
|
whatsapp.chats, important
|
|
267
207
|
"""
|
|
268
|
-
# Trigger authentication
|
|
269
208
|
self._authenticator()
|
|
270
|
-
|
|
271
209
|
user_id = self.api_key
|
|
272
210
|
chats = whatsapp_list_chats(
|
|
273
|
-
query=query,
|
|
274
|
-
limit=limit,
|
|
275
|
-
page=page,
|
|
276
|
-
include_last_message=include_last_message,
|
|
277
|
-
sort_by=sort_by,
|
|
278
|
-
user_id=user_id,
|
|
211
|
+
query=query, limit=limit, page=page, include_last_message=include_last_message, sort_by=sort_by, user_id=user_id
|
|
279
212
|
)
|
|
280
213
|
return chats
|
|
281
214
|
|
|
282
|
-
def get_chat_by_jid(
|
|
283
|
-
self,
|
|
284
|
-
chat_jid: str,
|
|
285
|
-
include_last_message: bool = True,
|
|
286
|
-
) -> dict[str, Any]:
|
|
215
|
+
async def get_chat_by_jid(self, chat_jid: str, include_last_message: bool = True) -> dict[str, Any]:
|
|
287
216
|
"""
|
|
288
217
|
Retrieves metadata for a specific WhatsApp chat (direct or group) using its unique JID. It can optionally include the most recent message. This precise JID-based lookup distinguishes it from `get_direct_chat_by_contact`, which uses a phone number, and `list_chats`, which performs a broader search.
|
|
289
218
|
|
|
@@ -302,18 +231,12 @@ class WhatsappApp(BaseApplication):
|
|
|
302
231
|
"""
|
|
303
232
|
if chat_jid is None:
|
|
304
233
|
raise ValueError("Missing required parameter 'chat_jid'.")
|
|
305
|
-
|
|
306
|
-
# Trigger authentication
|
|
307
234
|
self._authenticator()
|
|
308
|
-
|
|
309
235
|
user_id = self.api_key
|
|
310
236
|
chat = whatsapp_get_chat(chat_jid, include_last_message, user_id)
|
|
311
237
|
return chat
|
|
312
238
|
|
|
313
|
-
def get_direct_chat_by_phone_number(
|
|
314
|
-
self,
|
|
315
|
-
sender_phone_number: str,
|
|
316
|
-
) -> dict[str, Any]:
|
|
239
|
+
async def get_direct_chat_by_phone_number(self, sender_phone_number: str) -> dict[str, Any]:
|
|
317
240
|
"""
|
|
318
241
|
Retrieves metadata for a direct (one-on-one) WhatsApp chat using a contact's phone number. Unlike `get_chat` which requires a JID, this provides a simpler way to find direct conversations. Returns a dictionary containing the chat's details, such as its JID and name.
|
|
319
242
|
|
|
@@ -331,20 +254,12 @@ class WhatsappApp(BaseApplication):
|
|
|
331
254
|
"""
|
|
332
255
|
if sender_phone_number is None:
|
|
333
256
|
raise ValueError("Missing required parameter 'sender_phone_number'.")
|
|
334
|
-
|
|
335
|
-
# Trigger authentication
|
|
336
257
|
self._authenticator()
|
|
337
|
-
|
|
338
258
|
user_id = self.api_key
|
|
339
259
|
chat = whatsapp_get_direct_chat_by_contact(sender_phone_number, user_id)
|
|
340
260
|
return chat
|
|
341
261
|
|
|
342
|
-
def list_chats_by_contact_jid(
|
|
343
|
-
self,
|
|
344
|
-
jid: str,
|
|
345
|
-
limit: int = 20,
|
|
346
|
-
page: int = 0,
|
|
347
|
-
) -> list[dict[str, Any]]:
|
|
262
|
+
async def list_chats_by_contact_jid(self, jid: str, limit: int = 20, page: int = 0) -> list[dict[str, Any]]:
|
|
348
263
|
"""
|
|
349
264
|
Retrieves a paginated list of all WhatsApp chats, including direct messages and groups, that a specific contact participates in. The contact is identified by their unique JID. This differs from `get_direct_chat_by_contact` which only finds one-on-one chats.
|
|
350
265
|
|
|
@@ -364,18 +279,12 @@ class WhatsappApp(BaseApplication):
|
|
|
364
279
|
"""
|
|
365
280
|
if jid is None:
|
|
366
281
|
raise ValueError("Missing required parameter 'jid'.")
|
|
367
|
-
|
|
368
|
-
# Trigger authentication
|
|
369
282
|
self._authenticator()
|
|
370
|
-
|
|
371
283
|
user_id = self.api_key
|
|
372
284
|
chats = whatsapp_get_contact_chats(jid, limit, page, user_id)
|
|
373
285
|
return chats
|
|
374
286
|
|
|
375
|
-
def get_last_message_by_jid(
|
|
376
|
-
self,
|
|
377
|
-
jid: str,
|
|
378
|
-
) -> str:
|
|
287
|
+
async def get_last_message_by_jid(self, jid: str) -> str:
|
|
379
288
|
"""
|
|
380
289
|
Retrieves the content of the most recent message involving a specific contact, identified by their JID. It authenticates the user and returns the message directly as a string, offering a quick way to view the last communication without fetching full message objects or chat histories.
|
|
381
290
|
|
|
@@ -393,20 +302,12 @@ class WhatsappApp(BaseApplication):
|
|
|
393
302
|
"""
|
|
394
303
|
if jid is None:
|
|
395
304
|
raise ValueError("Missing required parameter 'jid'.")
|
|
396
|
-
|
|
397
|
-
# Trigger authentication
|
|
398
305
|
self._authenticator()
|
|
399
|
-
|
|
400
306
|
user_id = self.api_key
|
|
401
307
|
message = whatsapp_get_last_interaction(jid, user_id)
|
|
402
308
|
return message
|
|
403
309
|
|
|
404
|
-
def get_message_context(
|
|
405
|
-
self,
|
|
406
|
-
message_id: str,
|
|
407
|
-
before: int = 5,
|
|
408
|
-
after: int = 5,
|
|
409
|
-
) -> dict[str, Any]:
|
|
310
|
+
async def get_message_context(self, message_id: str, before: int = 5, after: int = 5) -> dict[str, Any]:
|
|
410
311
|
"""
|
|
411
312
|
Fetches the conversational context surrounding a specific WhatsApp message ID. It retrieves a configurable number of messages immediately preceding and following the target message. This provides a focused view of a dialogue, unlike `list_messages` which performs broader, filter-based searches.
|
|
412
313
|
|
|
@@ -426,19 +327,12 @@ class WhatsappApp(BaseApplication):
|
|
|
426
327
|
"""
|
|
427
328
|
if message_id is None:
|
|
428
329
|
raise ValueError("Missing required parameter 'message_id'.")
|
|
429
|
-
|
|
430
|
-
# Trigger authentication
|
|
431
330
|
self._authenticator()
|
|
432
|
-
|
|
433
331
|
user_id = self.api_key
|
|
434
332
|
context = whatsapp_get_message_context(message_id, before, after, user_id)
|
|
435
333
|
return context
|
|
436
334
|
|
|
437
|
-
def send_text_message(
|
|
438
|
-
self,
|
|
439
|
-
recipient: str,
|
|
440
|
-
message: str,
|
|
441
|
-
) -> dict[str, Any]:
|
|
335
|
+
async def send_text_message(self, recipient: str, message: str) -> dict[str, Any]:
|
|
442
336
|
"""
|
|
443
337
|
Authenticates the user and sends a text message to a specified WhatsApp recipient. The recipient can be an individual (via phone number) or a group (via JID). It returns a dictionary indicating the operation's success status and a corresponding message.
|
|
444
338
|
|
|
@@ -460,23 +354,12 @@ class WhatsappApp(BaseApplication):
|
|
|
460
354
|
raise ValueError("Missing required parameter 'recipient'.")
|
|
461
355
|
if message is None:
|
|
462
356
|
raise ValueError("Missing required parameter 'message'.")
|
|
463
|
-
|
|
464
|
-
# Trigger authentication
|
|
465
357
|
self._authenticator()
|
|
466
|
-
|
|
467
358
|
user_id = self.api_key
|
|
468
|
-
# Call the whatsapp_send_message function with the unified recipient parameter
|
|
469
359
|
success, status_message = whatsapp_send_message(recipient, message, user_id)
|
|
470
|
-
return {
|
|
471
|
-
"success": success,
|
|
472
|
-
"message": status_message,
|
|
473
|
-
}
|
|
360
|
+
return {"success": success, "message": status_message}
|
|
474
361
|
|
|
475
|
-
def send_attachment(
|
|
476
|
-
self,
|
|
477
|
-
recipient: str,
|
|
478
|
-
media_path: str,
|
|
479
|
-
) -> dict[str, Any]:
|
|
362
|
+
async def send_attachment(self, recipient: str, media_path: str) -> dict[str, Any]:
|
|
480
363
|
"""
|
|
481
364
|
Sends a media file (image, video, document, raw audio) as a standard attachment to a WhatsApp contact or group using their phone number or JID. Unlike `send_audio_message`, which creates a playable voice note, this function handles general file transfers. Returns a success status dictionary.
|
|
482
365
|
|
|
@@ -498,23 +381,12 @@ class WhatsappApp(BaseApplication):
|
|
|
498
381
|
raise ValueError("Missing required parameter 'recipient'.")
|
|
499
382
|
if media_path is None:
|
|
500
383
|
raise ValueError("Missing required parameter 'media_path'.")
|
|
501
|
-
|
|
502
|
-
# Trigger authentication
|
|
503
384
|
self._authenticator()
|
|
504
|
-
|
|
505
385
|
user_id = self.api_key
|
|
506
|
-
# Call the whatsapp_send_file function
|
|
507
386
|
success, status_message = whatsapp_send_file(recipient, media_path, user_id)
|
|
508
|
-
return {
|
|
509
|
-
"success": success,
|
|
510
|
-
"message": status_message,
|
|
511
|
-
}
|
|
387
|
+
return {"success": success, "message": status_message}
|
|
512
388
|
|
|
513
|
-
def send_voice_message(
|
|
514
|
-
self,
|
|
515
|
-
recipient: str,
|
|
516
|
-
media_path: str,
|
|
517
|
-
) -> dict[str, Any]:
|
|
389
|
+
async def send_voice_message(self, recipient: str, media_path: str) -> dict[str, Any]:
|
|
518
390
|
"""
|
|
519
391
|
Sends a local audio file as a playable WhatsApp voice message, converting it to the required format. Unlike `send_file` which sends audio as a document attachment, this function formats the audio as a voice note. It can be sent to an individual contact or a group chat.
|
|
520
392
|
|
|
@@ -536,24 +408,12 @@ class WhatsappApp(BaseApplication):
|
|
|
536
408
|
raise ValueError("Missing required parameter 'recipient'.")
|
|
537
409
|
if media_path is None:
|
|
538
410
|
raise ValueError("Missing required parameter 'media_path'.")
|
|
539
|
-
|
|
540
|
-
# Trigger authentication
|
|
541
411
|
self._authenticator()
|
|
542
|
-
|
|
543
412
|
user_id = self.api_key
|
|
544
|
-
success, status_message = whatsapp_audio_voice_message(
|
|
545
|
-
|
|
546
|
-
)
|
|
547
|
-
return {
|
|
548
|
-
"success": success,
|
|
549
|
-
"message": status_message,
|
|
550
|
-
}
|
|
413
|
+
success, status_message = whatsapp_audio_voice_message(recipient, media_path, user_id)
|
|
414
|
+
return {"success": success, "message": status_message}
|
|
551
415
|
|
|
552
|
-
def download_media_from_message(
|
|
553
|
-
self,
|
|
554
|
-
message_id: str,
|
|
555
|
-
chat_jid: str,
|
|
556
|
-
) -> dict[str, Any]:
|
|
416
|
+
async def download_media_from_message(self, message_id: str, chat_jid: str) -> dict[str, Any]:
|
|
557
417
|
"""
|
|
558
418
|
Downloads media from a specific WhatsApp message, identified by its ID and chat JID. It saves the content to a local file and returns the file's path upon success. The function automatically handles user authentication before initiating the download.
|
|
559
419
|
|
|
@@ -574,24 +434,13 @@ class WhatsappApp(BaseApplication):
|
|
|
574
434
|
raise ValueError("Missing required parameter 'message_id'.")
|
|
575
435
|
if chat_jid is None:
|
|
576
436
|
raise ValueError("Missing required parameter 'chat_jid'.")
|
|
577
|
-
|
|
578
|
-
# Trigger authentication
|
|
579
437
|
self._authenticator()
|
|
580
|
-
|
|
581
438
|
user_id = self.api_key
|
|
582
439
|
file_path = whatsapp_download_media(message_id, chat_jid, user_id)
|
|
583
|
-
|
|
584
440
|
if file_path:
|
|
585
|
-
return {
|
|
586
|
-
"success": True,
|
|
587
|
-
"message": "Media downloaded successfully",
|
|
588
|
-
"file_path": file_path,
|
|
589
|
-
}
|
|
441
|
+
return {"success": True, "message": "Media downloaded successfully", "file_path": file_path}
|
|
590
442
|
else:
|
|
591
|
-
return {
|
|
592
|
-
"success": False,
|
|
593
|
-
"message": "Failed to download media",
|
|
594
|
-
}
|
|
443
|
+
return {"success": False, "message": "Failed to download media"}
|
|
595
444
|
|
|
596
445
|
def list_tools(self):
|
|
597
446
|
"""
|
|
@@ -58,14 +58,10 @@ def convert_to_opus_ogg(input_file, output_file=None, bitrate="32k", sample_rate
|
|
|
58
58
|
|
|
59
59
|
try:
|
|
60
60
|
# Run the ffmpeg command and capture output
|
|
61
|
-
subprocess.run(
|
|
62
|
-
cmd, capture_output=True, text=True, check=True
|
|
63
|
-
)
|
|
61
|
+
subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
64
62
|
return output_file
|
|
65
63
|
except subprocess.CalledProcessError as e:
|
|
66
|
-
raise RuntimeError(
|
|
67
|
-
f"Failed to convert audio. You likely need to install ffmpeg {e.stderr}"
|
|
68
|
-
)
|
|
64
|
+
raise RuntimeError(f"Failed to convert audio. You likely need to install ffmpeg {e.stderr}")
|
|
69
65
|
|
|
70
66
|
|
|
71
67
|
def convert_to_opus_ogg_temp(input_file, bitrate="32k", sample_rate=24000):
|
|
@@ -54,9 +54,7 @@ class MessageContext:
|
|
|
54
54
|
after: list[Message]
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def _make_api_request(
|
|
58
|
-
endpoint: str, method: str = "GET", data: dict = None, user_id: str = "default_user"
|
|
59
|
-
) -> dict:
|
|
57
|
+
def _make_api_request(endpoint: str, method: str = "GET", data: dict = None, user_id: str = "default_user") -> dict:
|
|
60
58
|
"""Make HTTP request to WhatsApp Bridge API."""
|
|
61
59
|
url = f"{WHATSAPP_API_BASE_URL}/api/{endpoint}"
|
|
62
60
|
|
|
@@ -87,9 +85,7 @@ def _make_api_request(
|
|
|
87
85
|
|
|
88
86
|
def get_sender_name(sender_jid: str, user_id: str = "default_user") -> str:
|
|
89
87
|
"""Get sender name via API call."""
|
|
90
|
-
result = _make_api_request(
|
|
91
|
-
"sender_name", data={"sender_jid": sender_jid}, user_id=user_id
|
|
92
|
-
)
|
|
88
|
+
result = _make_api_request("sender_name", data={"sender_jid": sender_jid}, user_id=user_id)
|
|
93
89
|
|
|
94
90
|
if "error" in result:
|
|
95
91
|
return sender_jid
|
|
@@ -97,9 +93,7 @@ def get_sender_name(sender_jid: str, user_id: str = "default_user") -> str:
|
|
|
97
93
|
return result.get("name", sender_jid)
|
|
98
94
|
|
|
99
95
|
|
|
100
|
-
def format_message(
|
|
101
|
-
message: Message, show_chat_info: bool = True, user_id: str = "default_user"
|
|
102
|
-
) -> str:
|
|
96
|
+
def format_message(message: Message, show_chat_info: bool = True, user_id: str = "default_user") -> str:
|
|
103
97
|
"""Print a single message with consistent formatting."""
|
|
104
98
|
output = ""
|
|
105
99
|
|
|
@@ -113,18 +107,14 @@ def format_message(
|
|
|
113
107
|
content_prefix = f"[{message.media_type} - Message ID: {message.id} - Chat JID: {message.chat_jid}] "
|
|
114
108
|
|
|
115
109
|
try:
|
|
116
|
-
sender_name = (
|
|
117
|
-
get_sender_name(message.sender, user_id) if not message.is_from_me else "Me"
|
|
118
|
-
)
|
|
110
|
+
sender_name = get_sender_name(message.sender, user_id) if not message.is_from_me else "Me"
|
|
119
111
|
output += f"From: {sender_name}: {content_prefix}{message.content}\n"
|
|
120
112
|
except Exception:
|
|
121
113
|
pass
|
|
122
114
|
return output
|
|
123
115
|
|
|
124
116
|
|
|
125
|
-
def format_messages_list(
|
|
126
|
-
messages: list[Message], show_chat_info: bool = True, user_id: str = "default_user"
|
|
127
|
-
) -> str:
|
|
117
|
+
def format_messages_list(messages: list[Message], show_chat_info: bool = True, user_id: str = "default_user") -> str:
|
|
128
118
|
output = ""
|
|
129
119
|
if not messages:
|
|
130
120
|
output += "No messages to display."
|
|
@@ -173,9 +163,7 @@ def list_messages(
|
|
|
173
163
|
return result.get("messages", "No messages found")
|
|
174
164
|
|
|
175
165
|
|
|
176
|
-
def get_message_context(
|
|
177
|
-
message_id: str, before: int = 5, after: int = 5, user_id: str = "default_user"
|
|
178
|
-
) -> MessageContext:
|
|
166
|
+
def get_message_context(message_id: str, before: int = 5, after: int = 5, user_id: str = "default_user") -> MessageContext:
|
|
179
167
|
"""Get context around a specific message via API."""
|
|
180
168
|
params = {"message_id": message_id, "before": before, "after": after}
|
|
181
169
|
|
|
@@ -222,9 +210,7 @@ def list_chats(
|
|
|
222
210
|
chat = Chat(
|
|
223
211
|
jid=chat_data["jid"],
|
|
224
212
|
name=chat_data.get("name"),
|
|
225
|
-
last_message_time=datetime.fromisoformat(chat_data["last_message_time"])
|
|
226
|
-
if chat_data.get("last_message_time")
|
|
227
|
-
else None,
|
|
213
|
+
last_message_time=datetime.fromisoformat(chat_data["last_message_time"]) if chat_data.get("last_message_time") else None,
|
|
228
214
|
last_message=chat_data.get("last_message"),
|
|
229
215
|
last_sender=chat_data.get("last_sender"),
|
|
230
216
|
last_is_from_me=chat_data.get("last_is_from_me"),
|
|
@@ -255,9 +241,7 @@ def search_contacts(query: str, user_id: str = "default_user") -> list[Contact]:
|
|
|
255
241
|
return contacts
|
|
256
242
|
|
|
257
243
|
|
|
258
|
-
def get_contact_chats(
|
|
259
|
-
jid: str, limit: int = 20, page: int = 0, user_id: str = "default_user"
|
|
260
|
-
) -> list[Chat]:
|
|
244
|
+
def get_contact_chats(jid: str, limit: int = 20, page: int = 0, user_id: str = "default_user") -> list[Chat]:
|
|
261
245
|
"""Get all chats involving the contact via API."""
|
|
262
246
|
params = {"jid": jid, "limit": limit, "page": page}
|
|
263
247
|
|
|
@@ -273,9 +257,7 @@ def get_contact_chats(
|
|
|
273
257
|
chat = Chat(
|
|
274
258
|
jid=chat_data["jid"],
|
|
275
259
|
name=chat_data.get("name"),
|
|
276
|
-
last_message_time=datetime.fromisoformat(chat_data["last_message_time"])
|
|
277
|
-
if chat_data.get("last_message_time")
|
|
278
|
-
else None,
|
|
260
|
+
last_message_time=datetime.fromisoformat(chat_data["last_message_time"]) if chat_data.get("last_message_time") else None,
|
|
279
261
|
last_message=chat_data.get("last_message"),
|
|
280
262
|
last_sender=chat_data.get("last_sender"),
|
|
281
263
|
last_is_from_me=chat_data.get("last_is_from_me"),
|
|
@@ -295,9 +277,7 @@ def get_last_interaction(jid: str, user_id: str = "default_user") -> str:
|
|
|
295
277
|
return result.get("message", "No interaction found")
|
|
296
278
|
|
|
297
279
|
|
|
298
|
-
def get_chat(
|
|
299
|
-
chat_jid: str, include_last_message: bool = True, user_id: str = "default_user"
|
|
300
|
-
) -> Chat | None:
|
|
280
|
+
def get_chat(chat_jid: str, include_last_message: bool = True, user_id: str = "default_user") -> Chat | None:
|
|
301
281
|
"""Get chat metadata by JID via API."""
|
|
302
282
|
params = {"chat_jid": chat_jid, "include_last_message": include_last_message}
|
|
303
283
|
|
|
@@ -313,18 +293,14 @@ def get_chat(
|
|
|
313
293
|
return Chat(
|
|
314
294
|
jid=chat_data["jid"],
|
|
315
295
|
name=chat_data.get("name"),
|
|
316
|
-
last_message_time=datetime.fromisoformat(chat_data["last_message_time"])
|
|
317
|
-
if chat_data.get("last_message_time")
|
|
318
|
-
else None,
|
|
296
|
+
last_message_time=datetime.fromisoformat(chat_data["last_message_time"]) if chat_data.get("last_message_time") else None,
|
|
319
297
|
last_message=chat_data.get("last_message"),
|
|
320
298
|
last_sender=chat_data.get("last_sender"),
|
|
321
299
|
last_is_from_me=chat_data.get("last_is_from_me"),
|
|
322
300
|
)
|
|
323
301
|
|
|
324
302
|
|
|
325
|
-
def get_direct_chat_by_contact(
|
|
326
|
-
sender_phone_number: str, user_id: str = "default_user"
|
|
327
|
-
) -> Chat | None:
|
|
303
|
+
def get_direct_chat_by_contact(sender_phone_number: str, user_id: str = "default_user") -> Chat | None:
|
|
328
304
|
"""Get chat metadata by sender phone number via API."""
|
|
329
305
|
result = _make_api_request(
|
|
330
306
|
"direct_chat",
|
|
@@ -342,18 +318,14 @@ def get_direct_chat_by_contact(
|
|
|
342
318
|
return Chat(
|
|
343
319
|
jid=chat_data["jid"],
|
|
344
320
|
name=chat_data.get("name"),
|
|
345
|
-
last_message_time=datetime.fromisoformat(chat_data["last_message_time"])
|
|
346
|
-
if chat_data.get("last_message_time")
|
|
347
|
-
else None,
|
|
321
|
+
last_message_time=datetime.fromisoformat(chat_data["last_message_time"]) if chat_data.get("last_message_time") else None,
|
|
348
322
|
last_message=chat_data.get("last_message"),
|
|
349
323
|
last_sender=chat_data.get("last_sender"),
|
|
350
324
|
last_is_from_me=chat_data.get("last_is_from_me"),
|
|
351
325
|
)
|
|
352
326
|
|
|
353
327
|
|
|
354
|
-
def send_message(
|
|
355
|
-
recipient: str, message: str, user_id: str = "default_user"
|
|
356
|
-
) -> tuple[bool, str]:
|
|
328
|
+
def send_message(recipient: str, message: str, user_id: str = "default_user") -> tuple[bool, str]:
|
|
357
329
|
"""Send message via API."""
|
|
358
330
|
payload = {"user_id": user_id, "recipient": recipient, "message": message}
|
|
359
331
|
|
|
@@ -365,9 +337,7 @@ def send_message(
|
|
|
365
337
|
return result.get("success", False), result.get("message", "Unknown response")
|
|
366
338
|
|
|
367
339
|
|
|
368
|
-
def send_file(
|
|
369
|
-
recipient: str, media_path: str, user_id: str = "default_user"
|
|
370
|
-
) -> tuple[bool, str]:
|
|
340
|
+
def send_file(recipient: str, media_path: str, user_id: str = "default_user") -> tuple[bool, str]:
|
|
371
341
|
"""Send file via API."""
|
|
372
342
|
payload = {"user_id": user_id, "recipient": recipient, "media_path": media_path}
|
|
373
343
|
|
|
@@ -379,9 +349,7 @@ def send_file(
|
|
|
379
349
|
return result.get("success", False), result.get("message", "Unknown response")
|
|
380
350
|
|
|
381
351
|
|
|
382
|
-
def send_audio_message(
|
|
383
|
-
recipient: str, media_path: str, user_id: str = "default_user"
|
|
384
|
-
) -> tuple[bool, str]:
|
|
352
|
+
def send_audio_message(recipient: str, media_path: str, user_id: str = "default_user") -> tuple[bool, str]:
|
|
385
353
|
"""Send audio message via API."""
|
|
386
354
|
if not media_path.endswith(".ogg"):
|
|
387
355
|
try:
|
|
@@ -402,9 +370,7 @@ def send_audio_message(
|
|
|
402
370
|
return result.get("success", False), result.get("message", "Unknown response")
|
|
403
371
|
|
|
404
372
|
|
|
405
|
-
def download_media(
|
|
406
|
-
message_id: str, chat_jid: str, user_id: str = "default_user"
|
|
407
|
-
) -> str | None:
|
|
373
|
+
def download_media(message_id: str, chat_jid: str, user_id: str = "default_user") -> str | None:
|
|
408
374
|
"""Download media from a message via API."""
|
|
409
375
|
payload = {"user_id": user_id, "message_id": message_id, "chat_jid": chat_jid}
|
|
410
376
|
|