universal-mcp-applications 0.1.33__py3-none-any.whl → 0.1.39rc8__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.

Potentially problematic release.


This version of universal-mcp-applications might be problematic. Click here for more details.

Files changed (113) hide show
  1. universal_mcp/applications/ahrefs/app.py +92 -238
  2. universal_mcp/applications/airtable/app.py +23 -122
  3. universal_mcp/applications/apollo/app.py +122 -475
  4. universal_mcp/applications/asana/app.py +605 -1755
  5. universal_mcp/applications/aws_s3/app.py +36 -103
  6. universal_mcp/applications/bill/app.py +644 -2055
  7. universal_mcp/applications/box/app.py +1246 -4159
  8. universal_mcp/applications/braze/app.py +410 -1476
  9. universal_mcp/applications/browser_use/README.md +15 -1
  10. universal_mcp/applications/browser_use/__init__.py +1 -0
  11. universal_mcp/applications/browser_use/app.py +86 -24
  12. universal_mcp/applications/cal_com_v2/app.py +207 -625
  13. universal_mcp/applications/calendly/app.py +103 -242
  14. universal_mcp/applications/canva/app.py +75 -140
  15. universal_mcp/applications/clickup/app.py +331 -798
  16. universal_mcp/applications/coda/app.py +240 -520
  17. universal_mcp/applications/confluence/app.py +497 -1285
  18. universal_mcp/applications/contentful/app.py +36 -151
  19. universal_mcp/applications/crustdata/app.py +42 -121
  20. universal_mcp/applications/dialpad/app.py +451 -924
  21. universal_mcp/applications/digitalocean/app.py +2071 -6082
  22. universal_mcp/applications/domain_checker/app.py +3 -54
  23. universal_mcp/applications/e2b/app.py +14 -64
  24. universal_mcp/applications/elevenlabs/app.py +9 -47
  25. universal_mcp/applications/exa/README.md +8 -4
  26. universal_mcp/applications/exa/app.py +408 -186
  27. universal_mcp/applications/falai/app.py +24 -101
  28. universal_mcp/applications/figma/app.py +91 -175
  29. universal_mcp/applications/file_system/app.py +2 -13
  30. universal_mcp/applications/firecrawl/app.py +186 -163
  31. universal_mcp/applications/fireflies/app.py +59 -281
  32. universal_mcp/applications/fpl/app.py +92 -529
  33. universal_mcp/applications/fpl/utils/fixtures.py +15 -49
  34. universal_mcp/applications/fpl/utils/helper.py +25 -89
  35. universal_mcp/applications/fpl/utils/league_utils.py +20 -64
  36. universal_mcp/applications/ghost_content/app.py +66 -175
  37. universal_mcp/applications/github/app.py +28 -65
  38. universal_mcp/applications/gong/app.py +140 -300
  39. universal_mcp/applications/google_calendar/app.py +26 -78
  40. universal_mcp/applications/google_docs/app.py +98 -202
  41. universal_mcp/applications/google_drive/app.py +194 -793
  42. universal_mcp/applications/google_gemini/app.py +27 -62
  43. universal_mcp/applications/google_mail/README.md +1 -0
  44. universal_mcp/applications/google_mail/app.py +93 -214
  45. universal_mcp/applications/google_searchconsole/app.py +25 -58
  46. universal_mcp/applications/google_sheet/app.py +171 -624
  47. universal_mcp/applications/google_sheet/helper.py +26 -53
  48. universal_mcp/applications/hashnode/app.py +57 -269
  49. universal_mcp/applications/heygen/app.py +77 -155
  50. universal_mcp/applications/http_tools/app.py +10 -32
  51. universal_mcp/applications/hubspot/README.md +1 -1
  52. universal_mcp/applications/hubspot/app.py +7508 -99
  53. universal_mcp/applications/jira/app.py +2419 -8334
  54. universal_mcp/applications/klaviyo/app.py +737 -1619
  55. universal_mcp/applications/linkedin/README.md +5 -0
  56. universal_mcp/applications/linkedin/app.py +332 -227
  57. universal_mcp/applications/mailchimp/app.py +696 -1851
  58. universal_mcp/applications/markitdown/app.py +8 -20
  59. universal_mcp/applications/miro/app.py +333 -815
  60. universal_mcp/applications/ms_teams/app.py +85 -207
  61. universal_mcp/applications/neon/app.py +144 -250
  62. universal_mcp/applications/notion/app.py +36 -51
  63. universal_mcp/applications/onedrive/app.py +26 -48
  64. universal_mcp/applications/openai/app.py +42 -165
  65. universal_mcp/applications/outlook/README.md +22 -9
  66. universal_mcp/applications/outlook/app.py +403 -141
  67. universal_mcp/applications/perplexity/README.md +2 -1
  68. universal_mcp/applications/perplexity/app.py +162 -20
  69. universal_mcp/applications/pipedrive/app.py +1021 -3331
  70. universal_mcp/applications/posthog/app.py +272 -541
  71. universal_mcp/applications/reddit/app.py +61 -160
  72. universal_mcp/applications/resend/app.py +41 -107
  73. universal_mcp/applications/retell/app.py +23 -50
  74. universal_mcp/applications/rocketlane/app.py +250 -963
  75. universal_mcp/applications/scraper/app.py +67 -125
  76. universal_mcp/applications/semanticscholar/app.py +36 -78
  77. universal_mcp/applications/semrush/app.py +43 -77
  78. universal_mcp/applications/sendgrid/app.py +826 -1576
  79. universal_mcp/applications/sentry/app.py +444 -1079
  80. universal_mcp/applications/serpapi/app.py +40 -143
  81. universal_mcp/applications/sharepoint/app.py +27 -49
  82. universal_mcp/applications/shopify/app.py +1743 -4479
  83. universal_mcp/applications/shortcut/app.py +272 -534
  84. universal_mcp/applications/slack/app.py +41 -123
  85. universal_mcp/applications/spotify/app.py +206 -405
  86. universal_mcp/applications/supabase/app.py +174 -283
  87. universal_mcp/applications/tavily/app.py +2 -2
  88. universal_mcp/applications/trello/app.py +853 -2816
  89. universal_mcp/applications/twilio/app.py +14 -50
  90. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  91. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  92. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  93. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  94. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  95. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  96. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  97. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  98. universal_mcp/applications/whatsapp/app.py +35 -186
  99. universal_mcp/applications/whatsapp/audio.py +2 -6
  100. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  101. universal_mcp/applications/whatsapp_business/app.py +86 -299
  102. universal_mcp/applications/wrike/app.py +80 -153
  103. universal_mcp/applications/yahoo_finance/app.py +19 -65
  104. universal_mcp/applications/youtube/app.py +120 -306
  105. universal_mcp/applications/zenquotes/app.py +3 -3
  106. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/METADATA +4 -2
  107. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/RECORD +109 -113
  108. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/WHEEL +1 -1
  109. universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
  110. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
  111. universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
  112. universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
  113. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/licenses/LICENSE +0 -0
@@ -1,42 +1,18 @@
1
1
  import logging
2
2
  import sys
3
3
  from typing import Any
4
-
5
4
  import dns.resolver
6
5
  import requests
7
6
  from universal_mcp.applications.application import APIApplication
8
7
  from universal_mcp.integrations import Integration
9
8
 
10
- # Configure logging
11
9
  logging.basicConfig(
12
- level=logging.INFO,
13
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
14
- handlers=[logging.StreamHandler(sys.stderr)],
10
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", handlers=[logging.StreamHandler(sys.stderr)]
15
11
  )
16
-
17
12
  logger = logging.getLogger("domain_checker")
18
-
19
- # Constants
20
13
  RDAP_BOOTSTRAP_URL = "https://data.iana.org/rdap/dns.json"
21
14
  USER_AGENT = "DomainCheckerBot/1.0"
22
-
23
- # Top TLDs to check
24
- TOP_TLDS = [
25
- "com",
26
- "net",
27
- "org",
28
- "io",
29
- "co",
30
- "app",
31
- "dev",
32
- "ai",
33
- "me",
34
- "info",
35
- "xyz",
36
- "online",
37
- "site",
38
- "tech",
39
- ]
15
+ TOP_TLDS = ["com", "net", "org", "io", "co", "app", "dev", "ai", "me", "info", "xyz", "online", "site", "tech"]
40
16
 
41
17
 
42
18
  class DomainCheckerApp(APIApplication):
@@ -52,22 +28,16 @@ class DomainCheckerApp(APIApplication):
52
28
  Fetches a domain's registration details from Registration Data Access Protocol (RDAP) servers. It dynamically selects the appropriate server URL based on the domain's TLD, with special handling for common ones. Returns the JSON data as a dictionary or None if the request fails or data is unavailable.
53
29
  """
54
30
  try:
55
- # Special case for .ch and .li domains
56
31
  tld = domain.split(".")[-1].lower()
57
32
  if tld in ["ch", "li"]:
58
33
  rdap_url = f"https://rdap.nic.{tld}/domain/{domain}"
59
- # Use common RDAP servers for known TLDs
60
34
  elif tld in ["com", "net"]:
61
35
  rdap_url = f"https://rdap.verisign.com/{tld}/v1/domain/{domain}"
62
36
  elif tld == "org":
63
- rdap_url = (
64
- f"https://rdap.publicinterestregistry.org/rdap/domain/{domain}"
65
- )
37
+ rdap_url = f"https://rdap.publicinterestregistry.org/rdap/domain/{domain}"
66
38
  else:
67
39
  rdap_url = f"https://rdap.org/domain/{domain}"
68
-
69
40
  headers = {"Accept": "application/rdap+json", "User-Agent": USER_AGENT}
70
-
71
41
  response = requests.get(rdap_url, headers=headers, timeout=5)
72
42
  if response.status_code == 200:
73
43
  return response.json()
@@ -122,21 +92,13 @@ class DomainCheckerApp(APIApplication):
122
92
  domain, availability, registration, dns, rdap, important
123
93
  """
124
94
  logger.info(f"Checking domain: {domain}")
125
-
126
- # First check DNS
127
95
  has_dns = await self._check_dns(domain)
128
-
129
96
  if has_dns:
130
- # Domain exists, get RDAP data if possible
131
97
  rdap_data = await self._get_rdap_data(domain)
132
-
133
98
  if rdap_data:
134
- # Extract data from RDAP
135
99
  registrar = "Unknown"
136
100
  reg_date = "Unknown"
137
101
  exp_date = "Unknown"
138
-
139
- # Extract registrar
140
102
  entities = rdap_data.get("entities", [])
141
103
  for entity in entities:
142
104
  if "registrar" in entity.get("roles", []):
@@ -146,15 +108,12 @@ class DomainCheckerApp(APIApplication):
146
108
  if entry[0] in ["fn", "org"] and len(entry) > 3:
147
109
  registrar = entry[3]
148
110
  break
149
-
150
- # Extract dates
151
111
  events = rdap_data.get("events", [])
152
112
  for event in events:
153
113
  if event.get("eventAction") == "registration":
154
114
  reg_date = event.get("eventDate", "Unknown")
155
115
  elif event.get("eventAction") == "expiration":
156
116
  exp_date = event.get("eventDate", "Unknown")
157
-
158
117
  return {
159
118
  "domain": domain,
160
119
  "status": "Registered",
@@ -175,8 +134,6 @@ class DomainCheckerApp(APIApplication):
175
134
  "rdap_data_available": False,
176
135
  "note": "Domain has DNS records but RDAP data couldn't be retrieved",
177
136
  }
178
-
179
- # Try RDAP one more time even if DNS not found
180
137
  rdap_data = await self._get_rdap_data(domain)
181
138
  if rdap_data:
182
139
  return {
@@ -189,8 +146,6 @@ class DomainCheckerApp(APIApplication):
189
146
  "rdap_data_available": True,
190
147
  "note": "Domain found in RDAP registry",
191
148
  }
192
-
193
- # If we get here, the domain is likely available
194
149
  return {
195
150
  "domain": domain,
196
151
  "status": "Available",
@@ -233,17 +188,12 @@ class DomainCheckerApp(APIApplication):
233
188
  tld, keyword, domain-search, availability, bulk-check, important
234
189
  """
235
190
  logger.info(f"Checking keyword: {keyword} across TLDs")
236
-
237
191
  available = []
238
192
  taken = []
239
-
240
- # Check each TLD in sequence
241
193
  for tld in TOP_TLDS:
242
194
  domain = f"{keyword}.{tld}"
243
195
  has_dns = await self._check_dns(domain)
244
-
245
196
  if not has_dns:
246
- # Double-check with RDAP if no DNS
247
197
  rdap_data = await self._get_rdap_data(domain)
248
198
  if not rdap_data:
249
199
  available.append(domain)
@@ -251,7 +201,6 @@ class DomainCheckerApp(APIApplication):
251
201
  taken.append(domain)
252
202
  else:
253
203
  taken.append(domain)
254
-
255
204
  return {
256
205
  "keyword": keyword,
257
206
  "tlds_checked": len(TOP_TLDS),
@@ -1,17 +1,12 @@
1
1
  import os
2
2
  from typing import Annotated, Any
3
-
4
3
  from loguru import logger
5
4
 
6
5
  try:
7
6
  from e2b_code_interpreter import Sandbox
8
-
9
7
  except ImportError:
10
8
  Sandbox = None
11
- logger.error(
12
- "Failed to import E2B Sandbox. Please ensure 'e2b_code_interpreter' is installed."
13
- )
14
-
9
+ logger.error("Failed to import E2B Sandbox. Please ensure 'e2b_code_interpreter' is installed.")
15
10
  from universal_mcp.applications.application import APIApplication
16
11
  from universal_mcp.exceptions import NotAuthorizedError, ToolError
17
12
  from universal_mcp.integrations import Integration
@@ -28,9 +23,7 @@ class E2bApp(APIApplication):
28
23
  super().__init__(name="e2b", integration=integration, **kwargs)
29
24
  self._e2b_api_key: str | None = None
30
25
  if Sandbox is None:
31
- logger.warning(
32
- "E2B Sandbox SDK is not available. E2B tools will not function."
33
- )
26
+ logger.warning("E2B Sandbox SDK is not available. E2B tools will not function.")
34
27
 
35
28
  @property
36
29
  def e2b_api_key(self) -> str:
@@ -40,54 +33,31 @@ class E2bApp(APIApplication):
40
33
  if self._e2b_api_key is None:
41
34
  if not self.integration:
42
35
  logger.error("E2B App: Integration not configured.")
43
- raise NotAuthorizedError(
44
- "Integration not configured for E2B App. Cannot retrieve API key."
45
- )
46
-
36
+ raise NotAuthorizedError("Integration not configured for E2B App. Cannot retrieve API key.")
47
37
  try:
48
38
  credentials = self.integration.get_credentials()
49
39
  except NotAuthorizedError as e:
50
- logger.error(
51
- f"E2B App: Authorization error when fetching credentials: {e.message}"
52
- )
53
- raise # Re-raise the original NotAuthorizedError
40
+ logger.error(f"E2B App: Authorization error when fetching credentials: {e.message}")
41
+ raise
54
42
  except Exception as e:
55
- logger.error(
56
- f"E2B App: Unexpected error when fetching credentials: {e}",
57
- exc_info=True,
58
- )
43
+ logger.error(f"E2B App: Unexpected error when fetching credentials: {e}", exc_info=True)
59
44
  raise NotAuthorizedError(f"Failed to get E2B credentials: {e}")
60
-
61
- api_key = (
62
- credentials.get("api_key")
63
- or credentials.get("API_KEY") # Check common variations
64
- or credentials.get("apiKey")
65
- )
66
-
45
+ api_key = credentials.get("api_key") or credentials.get("API_KEY") or credentials.get("apiKey")
67
46
  if not api_key:
68
47
  logger.error("E2B App: API key not found in credentials.")
69
48
  action_message = "API key for E2B is missing. Please ensure it's set in the store via MCP frontend or configuration."
70
- if hasattr(self.integration, "authorize") and callable(
71
- self.integration.authorize
72
- ):
49
+ if hasattr(self.integration, "authorize") and callable(self.integration.authorize):
73
50
  try:
74
51
  auth_details = self.integration.authorize()
75
52
  if isinstance(auth_details, str):
76
53
  action_message = auth_details
77
54
  elif isinstance(auth_details, dict) and "url" in auth_details:
78
- action_message = (
79
- f"Please authorize via: {auth_details['url']}"
80
- )
81
- elif (
82
- isinstance(auth_details, dict) and "message" in auth_details
83
- ):
55
+ action_message = f"Please authorize via: {auth_details['url']}"
56
+ elif isinstance(auth_details, dict) and "message" in auth_details:
84
57
  action_message = auth_details["message"]
85
58
  except Exception as auth_e:
86
- logger.warning(
87
- f"Could not retrieve specific authorization action for E2B: {auth_e}"
88
- )
59
+ logger.warning(f"Could not retrieve specific authorization action for E2B: {auth_e}")
89
60
  raise NotAuthorizedError(action_message)
90
-
91
61
  self._e2b_api_key = api_key
92
62
  logger.info("E2B API Key successfully retrieved and cached.")
93
63
  return self._e2b_api_key
@@ -95,40 +65,28 @@ class E2bApp(APIApplication):
95
65
  def _format_execution_output(self, execution: Any) -> str:
96
66
  """Helper function to format the E2B execution logs nicely."""
97
67
  output_parts = []
98
-
99
68
  try:
100
69
  logs = getattr(execution, "logs", None)
101
-
102
70
  if logs is not None:
103
- # Collect stdout
104
71
  if getattr(logs, "stdout", None):
105
72
  stdout_content = "".join(logs.stdout).strip()
106
73
  if stdout_content:
107
74
  output_parts.append(stdout_content)
108
-
109
- # Collect stderr
110
75
  if getattr(logs, "stderr", None):
111
76
  stderr_content = "".join(logs.stderr).strip()
112
77
  if stderr_content:
113
78
  output_parts.append(f"--- ERROR ---\n{stderr_content}")
114
-
115
- # Fallback: check execution.text (covers expressions returning values)
116
79
  if not output_parts and hasattr(execution, "text"):
117
80
  text_content = str(execution.text).strip()
118
81
  if text_content:
119
82
  output_parts.append(text_content)
120
-
121
83
  except Exception as e:
122
84
  output_parts.append(f"Failed to format execution output: {e}")
123
-
124
85
  if not output_parts:
125
86
  return "Execution finished with no output (stdout/stderr)."
126
-
127
87
  return "\n\n".join(output_parts)
128
88
 
129
- def execute_python_code(
130
- self, code: Annotated[str, "The Python code to execute."]
131
- ) -> str:
89
+ async def execute_python_code(self, code: Annotated[str, "The Python code to execute."]) -> str:
132
90
  """
133
91
  Executes a Python code string in a secure E2B sandbox. It authenticates using the configured API key, runs the code, and returns a formatted string containing the execution's output (stdout/stderr). It raises specific exceptions for authorization failures or general execution issues.
134
92
 
@@ -151,7 +109,6 @@ class E2bApp(APIApplication):
151
109
  raise ToolError("E2B Sandbox SDK (e2b_code_interpreter) is not installed.")
152
110
  if not code or not isinstance(code, str):
153
111
  raise ValueError("Provided code must be a non-empty string.")
154
-
155
112
  try:
156
113
  logger.info("Attempting to execute Python code in E2B Sandbox.")
157
114
  os.environ["E2B_API_KEY"] = self.e2b_api_key
@@ -164,17 +121,10 @@ class E2bApp(APIApplication):
164
121
  except Exception as e:
165
122
  logger.exception("E2B code execution failed.")
166
123
  lower = str(e).lower()
167
- if (
168
- "authentication" in lower
169
- or "api key" in lower
170
- or "401" in lower
171
- or "403" in lower
172
- ):
124
+ if "authentication" in lower or "api key" in lower or "401" in lower or ("403" in lower):
173
125
  raise NotAuthorizedError(f"E2B authentication/permission failed: {e}")
174
126
  raise ToolError(f"E2B code execution failed: {e}")
175
127
 
176
128
  def list_tools(self) -> list[callable]:
177
129
  """Lists the tools available from the E2bApp."""
178
- return [
179
- self.execute_python_code,
180
- ]
130
+ return [self.execute_python_code]
@@ -1,11 +1,9 @@
1
1
  import uuid
2
2
  from io import BytesIO
3
-
4
3
  import requests
5
4
  from universal_mcp.applications.application import APIApplication
6
5
  from universal_mcp.exceptions import NotAuthorizedError
7
6
  from universal_mcp.integrations import Integration
8
-
9
7
  from elevenlabs import ElevenLabs
10
8
  from universal_mcp.applications.file_system.app import FileSystemApp
11
9
 
@@ -24,24 +22,14 @@ class ElevenlabsApp(APIApplication):
24
22
  credentials = self.integration.get_credentials()
25
23
  if not credentials:
26
24
  raise NotAuthorizedError("No credentials found")
27
- api_key = (
28
- credentials.get("api_key")
29
- or credentials.get("API_KEY")
30
- or credentials.get("apiKey")
31
- )
25
+ api_key = credentials.get("api_key") or credentials.get("API_KEY") or credentials.get("apiKey")
32
26
  if not api_key:
33
27
  raise NotAuthorizedError("No api key found")
34
28
  self._client = ElevenLabs(api_key=api_key)
35
29
  return self._client
36
30
 
37
- # def get_voices(self):
38
- # return self.client.voices.list_voices()
39
-
40
31
  async def generate_speech_audio_url(
41
- self,
42
- text: str,
43
- voice_id: str = "21m00Tcm4TlvDq8ikWAM",
44
- model_id: str = "eleven_multilingual_v2",
32
+ self, text: str, voice_id: str = "21m00Tcm4TlvDq8ikWAM", model_id: str = "eleven_multilingual_v2"
45
33
  ) -> bytes:
46
34
  """
47
35
  Converts a text string into speech using the ElevenLabs API. The function then saves the generated audio to a temporary MP3 file and returns a public URL to access it, rather than the raw audio bytes.
@@ -59,26 +47,14 @@ class ElevenlabsApp(APIApplication):
59
47
  Tags:
60
48
  important
61
49
  """
62
- audio_generator = self.client.text_to_speech.convert(
63
- text=text,
64
- voice_id=voice_id,
65
- model_id=model_id,
66
- output_format="mp3_44100_128",
67
- )
68
-
69
- # Collect all audio chunks from the generator
50
+ audio_generator = self.client.text_to_speech.convert(text=text, voice_id=voice_id, model_id=model_id, output_format="mp3_44100_128")
70
51
  audio_data = b""
71
52
  for chunk in audio_generator:
72
53
  audio_data += chunk
73
-
74
- upload_result = await FileSystemApp.write_file(
75
- audio_data, f"/tmp/{uuid.uuid4()}.mp3"
76
- )
54
+ upload_result = await FileSystemApp.write_file(audio_data, f"/tmp/{uuid.uuid4()}.mp3")
77
55
  return upload_result["data"]["url"]
78
56
 
79
- async def speech_to_text(
80
- self, audio_file_path: str, language_code: str = "eng", diarize: bool = True
81
- ) -> str:
57
+ async def speech_to_text(self, audio_file_path: str, language_code: str = "eng", diarize: bool = True) -> str:
82
58
  """
83
59
  Transcribes an audio file into text using the ElevenLabs API. It supports language specification and speaker diarization, providing the inverse operation to the audio-generating `text_to_speech` method. Note: The docstring indicates this is a placeholder for an undocumented endpoint.
84
60
 
@@ -92,19 +68,12 @@ class ElevenlabsApp(APIApplication):
92
68
  important
93
69
  """
94
70
  transcription = self.client.speech_to_text.convert(
95
- file=audio_file_path,
96
- model_id="scribe_v1", # Model to use, for now only "scribe_v1" is supported
97
- tag_audio_events=True, # Tag audio events like laughter, applause, etc.
98
- language_code=language_code, # Language of the audio file. If set to None, the model will detect the language automatically.
99
- diarize=diarize, # Whether to annotate who is speaking
71
+ file=audio_file_path, model_id="scribe_v1", tag_audio_events=True, language_code=language_code, diarize=diarize
100
72
  )
101
73
  return transcription
102
74
 
103
75
  async def speech_to_speech(
104
- self,
105
- audio_url: str,
106
- voice_id: str = "21m00Tcm4TlvDq8ikWAM",
107
- model_id: str = "eleven_multilingual_sts_v2",
76
+ self, audio_url: str, voice_id: str = "21m00Tcm4TlvDq8ikWAM", model_id: str = "eleven_multilingual_sts_v2"
108
77
  ) -> bytes:
109
78
  """
110
79
  Downloads an audio file from a URL and converts the speech into a specified target voice using the ElevenLabs API. This function transforms the speaker's voice in an existing recording and returns the new audio data as bytes, distinct from creating audio from text.
@@ -123,19 +92,12 @@ class ElevenlabsApp(APIApplication):
123
92
  response = requests.get(audio_url)
124
93
  audio_data = BytesIO(response.content)
125
94
  response = self.client.speech_to_speech.convert(
126
- voice_id=voice_id,
127
- audio=audio_data,
128
- model_id=model_id,
129
- output_format="mp3_44100_128",
95
+ voice_id=voice_id, audio=audio_data, model_id=model_id, output_format="mp3_44100_128"
130
96
  )
131
97
  return response.content
132
98
 
133
99
  def list_tools(self):
134
- return [
135
- self.generate_speech_audio_url,
136
- self.speech_to_text,
137
- self.speech_to_speech,
138
- ]
100
+ return [self.generate_speech_audio_url, self.speech_to_text, self.speech_to_speech]
139
101
 
140
102
 
141
103
  async def demo_text_to_speech():
@@ -9,7 +9,11 @@ This is automatically generated from OpenAPI schema for the ExaApp API.
9
9
 
10
10
  | Tool | Description |
11
11
  |------|-------------|
12
- | `search_with_filters` | Executes a query against the Exa API's `/search` endpoint, returning a list of results. This function supports extensive filtering by search type, category, domains, publication dates, and specific text content to refine the search query and tailor the API's response. |
13
- | `find_similar_by_url` | Finds web pages semantically similar to a given URL. Unlike the `search` function, which uses a text query, this method takes a specific link and returns a list of related results, with options to filter by domain, publication date, and content. |
14
- | `fetch_page_content` | Retrieves and processes content from a list of URLs, returning full text, summaries, or highlights. Unlike the search function which finds links, this function fetches the actual page content, with optional support for live crawling to get the most up-to-date information. |
15
- | `answer` | Retrieves a direct, synthesized answer for a given query by calling the Exa `/answer` API endpoint. Unlike `search`, which returns web results, this function provides a conclusive response. It supports streaming, including source text, and selecting a search model. |
12
+ | `search` | Performs a semantic or keyword search across the web and returns ranked results. |
13
+ | `find_similar` | Retrieves webpages that are semantically similar to a provided URL. |
14
+ | `get_contents` | Deep-fetches the actual content of specific URLs or Result IDs. |
15
+ | `answer` | Synthesizes a direct, objective answer to a research question based on multiple web sources. |
16
+ | `create_research_task` | Initiates a long-running, autonomous research task that explores the web to fulfill complex instructions. |
17
+ | `get_research_task` | Retrieves the current status, metadata, and (if finished) final results of a research task. |
18
+ | `poll_research_task` | Blocks until a research task completes, fails, or times out. |
19
+ | `list_research_tasks` | Provides a paginated list of all past and current research tasks for auditing or recovery. |