dhisana 0.0.1.dev232__py3-none-any.whl → 0.0.1.dev234__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.
@@ -1229,13 +1229,14 @@ async def test_firefliesai(api_key: str) -> Dict[str, Any]:
1229
1229
 
1230
1230
 
1231
1231
  async def test_firecrawl(api_key: str) -> Dict[str, Any]:
1232
- """Quick check for Firecrawl API key validity."""
1233
- url = "https://api.firecrawl.com/v1/scrape"
1232
+ """Quick check for Firecrawl API key validity (official v1 endpoint)."""
1233
+ url = "https://api.firecrawl.dev/v1/scrape"
1234
1234
  headers = {
1235
- "x-api-key": api_key,
1235
+ "Authorization": f"Bearer {api_key}", # per Firecrawl v1 docs
1236
1236
  "Content-Type": "application/json",
1237
1237
  }
1238
1238
  payload = {"url": "https://example.com"}
1239
+
1239
1240
  try:
1240
1241
  async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
1241
1242
  async with session.post(url, headers=headers, json=payload) as response:
@@ -1262,6 +1263,41 @@ async def test_firecrawl(api_key: str) -> Dict[str, Any]:
1262
1263
  return {"success": False, "status_code": 0, "error_message": str(exc)}
1263
1264
 
1264
1265
 
1266
+ async def test_scraperapi(api_key: str) -> Dict[str, Any]:
1267
+ """Connectivity check for ScraperAPI using a simple NYTimes scrape."""
1268
+ url = "https://api.scraperapi.com/"
1269
+ params = {
1270
+ "api_key": api_key,
1271
+ "url": "https://example.com/", # lightweight public page to minimize credit usage
1272
+ "output_format": "markdown",
1273
+ }
1274
+ try:
1275
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
1276
+ async with session.get(url, params=params) as response:
1277
+ status = response.status
1278
+ body_text = await response.text()
1279
+
1280
+ if status != 200:
1281
+ snippet = body_text[:200] if body_text else None
1282
+ return {
1283
+ "success": False,
1284
+ "status_code": status,
1285
+ "error_message": snippet or f"Non-200 from ScraperAPI: {status}",
1286
+ }
1287
+
1288
+ if not body_text:
1289
+ return {
1290
+ "success": False,
1291
+ "status_code": status,
1292
+ "error_message": "ScraperAPI returned an empty response.",
1293
+ }
1294
+
1295
+ return {"success": True, "status_code": status, "error_message": None}
1296
+ except Exception as exc:
1297
+ logger.error(f"ScraperAPI connectivity test failed: {exc}")
1298
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1299
+
1300
+
1265
1301
  async def test_youtube(api_key: str) -> Dict[str, Any]:
1266
1302
  """
1267
1303
  Tests YouTube Data API v3 by making a simple search request.
@@ -1340,6 +1376,276 @@ async def test_youtube(api_key: str) -> Dict[str, Any]:
1340
1376
  return {"success": False, "status_code": 0, "error_message": str(exc)}
1341
1377
 
1342
1378
 
1379
+ async def test_orum(api_key: str) -> Dict[str, Any]:
1380
+ """
1381
+ Validate an Orum API key by calling a lightweight authenticated endpoint.
1382
+
1383
+ The base URL can be overridden with ORUM_API_BASE_URL if needed.
1384
+ """
1385
+ base_url = os.getenv("ORUM_API_BASE_URL", "https://api.orum.com")
1386
+ url = f"{base_url.rstrip('/')}/api/v1/users/me"
1387
+ headers = {
1388
+ "Authorization": f"Bearer {api_key}",
1389
+ "Accept": "application/json",
1390
+ }
1391
+
1392
+ try:
1393
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
1394
+ async with session.get(url, headers=headers) as response:
1395
+ status = response.status
1396
+ data = await safe_json(response)
1397
+
1398
+ if status == 200:
1399
+ return {"success": True, "status_code": status, "error_message": None}
1400
+
1401
+ message = None
1402
+ if isinstance(data, dict):
1403
+ message = data.get("message") or data.get("error") or data.get("detail")
1404
+ return {
1405
+ "success": False,
1406
+ "status_code": status,
1407
+ "error_message": message or f"Orum responded with {status}",
1408
+ }
1409
+ except Exception as exc:
1410
+ logger.error(f"Orum connectivity test failed: {exc}")
1411
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1412
+
1413
+
1414
+ async def test_aircall(app_id: str, api_token: str) -> Dict[str, Any]:
1415
+ """
1416
+ Validate Aircall credentials via a lightweight authenticated call.
1417
+ Uses HTTP Basic Auth (app_id:api_token).
1418
+ """
1419
+ url = "https://api.aircall.io/v1/users"
1420
+ params = {"per_page": 1}
1421
+
1422
+ try:
1423
+ auth = aiohttp.BasicAuth(app_id, api_token)
1424
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10), auth=auth) as session:
1425
+ async with session.get(url, params=params) as response:
1426
+ status = response.status
1427
+ data = await safe_json(response)
1428
+
1429
+ if status == 200 and isinstance(data, dict) and "users" in data:
1430
+ return {"success": True, "status_code": status, "error_message": None}
1431
+
1432
+ message = None
1433
+ if isinstance(data, dict):
1434
+ message = data.get("message") or data.get("error")
1435
+ return {
1436
+ "success": False,
1437
+ "status_code": status,
1438
+ "error_message": message or f"Aircall responded with {status}",
1439
+ }
1440
+ except Exception as exc:
1441
+ logger.error(f"Aircall connectivity test failed: {exc}")
1442
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1443
+
1444
+
1445
+ async def test_ringover(api_key: str) -> Dict[str, Any]:
1446
+ """
1447
+ Validate Ringover API key using a minimal authenticated request.
1448
+ """
1449
+ base_url = os.getenv("RINGOVER_API_BASE_URL", "https://public-api.ringover.com")
1450
+ url = f"{base_url.rstrip('/')}/v2/users"
1451
+ headers = {
1452
+ "X-API-KEY": api_key,
1453
+ "Accept": "application/json",
1454
+ }
1455
+ params = {"limit": 1}
1456
+
1457
+ try:
1458
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
1459
+ async with session.get(url, headers=headers, params=params) as response:
1460
+ status = response.status
1461
+ data = await safe_json(response)
1462
+
1463
+ if status == 200:
1464
+ return {"success": True, "status_code": status, "error_message": None}
1465
+
1466
+ message = None
1467
+ if isinstance(data, dict):
1468
+ message = data.get("message") or data.get("error") or data.get("detail")
1469
+ return {
1470
+ "success": False,
1471
+ "status_code": status,
1472
+ "error_message": message or f"Ringover responded with {status}",
1473
+ }
1474
+ except Exception as exc:
1475
+ logger.error(f"Ringover connectivity test failed: {exc}")
1476
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1477
+
1478
+
1479
+ async def test_dialpad(client_id: str, client_secret: str) -> Dict[str, Any]:
1480
+ """
1481
+ Validate Dialpad client credentials via client_credentials token exchange, then whoami.
1482
+ """
1483
+ base_url = os.getenv("DIALPAD_API_BASE_URL", "https://dialpad.com")
1484
+ token_url = f"{base_url.rstrip('/')}/oauth/token"
1485
+ whoami_url = f"{base_url.rstrip('/')}/api/v2/whoami"
1486
+
1487
+ try:
1488
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
1489
+ token_resp = await session.post(
1490
+ token_url,
1491
+ data={
1492
+ "grant_type": "client_credentials",
1493
+ "client_id": client_id,
1494
+ "client_secret": client_secret,
1495
+ },
1496
+ headers={"Accept": "application/json"},
1497
+ )
1498
+ token_status = token_resp.status
1499
+ token_data = await safe_json(token_resp)
1500
+
1501
+ access_token = None
1502
+ if isinstance(token_data, dict):
1503
+ access_token = token_data.get("access_token")
1504
+
1505
+ if token_status != 200 or not access_token:
1506
+ message = None
1507
+ if isinstance(token_data, dict):
1508
+ message = token_data.get("error_description") or token_data.get("error")
1509
+ return {
1510
+ "success": False,
1511
+ "status_code": token_status,
1512
+ "error_message": message or "Failed to obtain Dialpad access token.",
1513
+ }
1514
+
1515
+ headers = {
1516
+ "Authorization": f"Bearer {access_token}",
1517
+ "Accept": "application/json",
1518
+ }
1519
+ async with session.get(whoami_url, headers=headers) as response:
1520
+ status = response.status
1521
+ data = await safe_json(response)
1522
+
1523
+ if status == 200:
1524
+ return {"success": True, "status_code": status, "error_message": None}
1525
+
1526
+ message = None
1527
+ if isinstance(data, dict):
1528
+ message = data.get("message") or data.get("error") or data.get("detail")
1529
+ return {
1530
+ "success": False,
1531
+ "status_code": status,
1532
+ "error_message": message or f"Dialpad responded with {status}",
1533
+ }
1534
+ except Exception as exc:
1535
+ logger.error(f"Dialpad connectivity test failed: {exc}")
1536
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1537
+
1538
+
1539
+ async def test_nooks(api_key: str) -> Dict[str, Any]:
1540
+ """
1541
+ Validate Nooks.ai API key via a simple authenticated call.
1542
+ """
1543
+ base_url = os.getenv("NOOKS_API_BASE_URL", "https://api.nooks.ai")
1544
+ url = f"{base_url.rstrip('/')}/v1/users/me"
1545
+ headers = {
1546
+ "Authorization": f"Bearer {api_key}",
1547
+ "Accept": "application/json",
1548
+ }
1549
+
1550
+ try:
1551
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
1552
+ async with session.get(url, headers=headers) as response:
1553
+ status = response.status
1554
+ data = await safe_json(response)
1555
+
1556
+ if status == 200:
1557
+ return {"success": True, "status_code": status, "error_message": None}
1558
+
1559
+ message = None
1560
+ if isinstance(data, dict):
1561
+ message = data.get("message") or data.get("error") or data.get("detail")
1562
+ return {
1563
+ "success": False,
1564
+ "status_code": status,
1565
+ "error_message": message or f"Nooks.ai responded with {status}",
1566
+ }
1567
+ except Exception as exc:
1568
+ logger.error(f"Nooks.ai connectivity test failed: {exc}")
1569
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1570
+
1571
+
1572
+ async def test_commonroom(api_key: str) -> Dict[str, Any]:
1573
+ """Validate a Common Room API token via the token status endpoint."""
1574
+ url = "https://api.commonroom.io/community/v1/api-token-status"
1575
+ headers = {
1576
+ "Authorization": f"Bearer {api_key}",
1577
+ "Accept": "application/json",
1578
+ }
1579
+
1580
+ try:
1581
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
1582
+ async with session.get(url, headers=headers) as response:
1583
+ status = response.status
1584
+ data = await safe_json(response)
1585
+
1586
+ if status == 200:
1587
+ return {"success": True, "status_code": status, "error_message": None}
1588
+
1589
+ message = None
1590
+ if isinstance(data, dict):
1591
+ message = (
1592
+ data.get("message")
1593
+ or data.get("reason")
1594
+ or data.get("error")
1595
+ or data.get("docs")
1596
+ )
1597
+ return {
1598
+ "success": False,
1599
+ "status_code": status,
1600
+ "error_message": message or f"Common Room responded with {status}",
1601
+ }
1602
+ except Exception as exc:
1603
+ logger.error(f"Common Room connectivity test failed: {exc}")
1604
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1605
+
1606
+
1607
+ async def test_scarf(api_key: str) -> Dict[str, Any]:
1608
+ """
1609
+ Validate a Scarf API token via the lightweight /v2/search endpoint.
1610
+
1611
+ The endpoint requires only the bearer token and a simple query string.
1612
+ """
1613
+ url = "https://api.scarf.sh/v2/search"
1614
+ headers = {
1615
+ "Authorization": f"Bearer {api_key}",
1616
+ "Content-Type": "application/json",
1617
+ }
1618
+ payload = {"query": "dhisana connectivity test"}
1619
+
1620
+ try:
1621
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
1622
+ async with session.post(url, headers=headers, json=payload) as response:
1623
+ status = response.status
1624
+ data = await safe_json(response)
1625
+
1626
+ if status != 200:
1627
+ message = None
1628
+ if isinstance(data, dict):
1629
+ message = data.get("message") or data.get("error") or data.get("detail")
1630
+ return {
1631
+ "success": False,
1632
+ "status_code": status,
1633
+ "error_message": message or f"Scarf responded with {status}",
1634
+ }
1635
+
1636
+ if isinstance(data, dict) and "results" in data:
1637
+ return {"success": True, "status_code": status, "error_message": None}
1638
+
1639
+ return {
1640
+ "success": False,
1641
+ "status_code": status,
1642
+ "error_message": "Unexpected Scarf response payload.",
1643
+ }
1644
+ except Exception as exc:
1645
+ logger.error(f"Scarf connectivity test failed: {exc}")
1646
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1647
+
1648
+
1343
1649
  ###############################################################################
1344
1650
  # DATAGMA CONNECTIVITY
1345
1651
  ###############################################################################
@@ -1426,6 +1732,13 @@ async def test_connectivity(tool_config: List[Dict[str, Any]]) -> Dict[str, Dict
1426
1732
  "firefliesai": test_firefliesai,
1427
1733
  "firecrawl": test_firecrawl,
1428
1734
  "youtube": test_youtube,
1735
+ "orum": test_orum,
1736
+ "aircall": test_aircall, # handled specially to pass appId + apiToken
1737
+ "ringover": test_ringover,
1738
+ "dialpad": test_dialpad, # handled specially to pass client credentials
1739
+ "nooks": test_nooks,
1740
+ "commonRoom": test_commonroom,
1741
+ "scarf": test_scarf,
1429
1742
  "salesforce": test_salesforce,
1430
1743
  "clay": test_clay,
1431
1744
  "posthog": test_posthog,
@@ -1434,6 +1747,7 @@ async def test_connectivity(tool_config: List[Dict[str, Any]]) -> Dict[str, Dict
1434
1747
  "mailgun": test_mailgun,
1435
1748
  "sendgrid": test_sendgrid,
1436
1749
  "samgov": test_samgov,
1750
+ "scraperapi": test_scraperapi,
1437
1751
  }
1438
1752
 
1439
1753
  results: Dict[str, Dict[str, Any]] = {}
@@ -1602,6 +1916,40 @@ async def test_connectivity(tool_config: List[Dict[str, Any]]) -> Dict[str, Dict
1602
1916
  )
1603
1917
  continue
1604
1918
 
1919
+ # ------------------------------------------------------------------ #
1920
+ # Special-case: Aircall (app_id + api_token)
1921
+ # ------------------------------------------------------------------ #
1922
+ if tool_name == "aircall":
1923
+ app_id = next((c["value"] for c in config_entries if c["name"] == "apiId"), None)
1924
+ api_token = next((c["value"] for c in config_entries if c["name"] == "apiToken"), None)
1925
+ if not app_id or not api_token:
1926
+ results[tool_name] = {
1927
+ "success": False,
1928
+ "status_code": 0,
1929
+ "error_message": "Missing apiId or apiToken for Aircall.",
1930
+ }
1931
+ else:
1932
+ logger.info("Testing connectivity for Aircall…")
1933
+ results[tool_name] = await test_aircall(app_id, api_token)
1934
+ continue
1935
+
1936
+ # ------------------------------------------------------------------ #
1937
+ # Special-case: Dialpad (client credentials)
1938
+ # ------------------------------------------------------------------ #
1939
+ if tool_name == "dialpad":
1940
+ client_id = next((c["value"] for c in config_entries if c["name"] == "clientId"), None)
1941
+ client_secret = next((c["value"] for c in config_entries if c["name"] == "clientSecret"), None)
1942
+ if not client_id or not client_secret:
1943
+ results[tool_name] = {
1944
+ "success": False,
1945
+ "status_code": 0,
1946
+ "error_message": "Missing clientId or clientSecret for Dialpad.",
1947
+ }
1948
+ else:
1949
+ logger.info("Testing connectivity for Dialpad…")
1950
+ results[tool_name] = await test_dialpad(client_id, client_secret)
1951
+ continue
1952
+
1605
1953
  # ------------------------------------------------------------------ #
1606
1954
  # All other tools – expect an apiKey by default
1607
1955
  # ------------------------------------------------------------------ #
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev232
3
+ Version: 0.0.1.dev234
4
4
  Summary: A Python SDK for Dhisana AI Platform
5
5
  Home-page: https://github.com/dhisana-ai/dhisana-python-sdk
6
6
  Author: Admin
@@ -79,7 +79,7 @@ dhisana/utils/serperdev_google_jobs.py,sha256=m5_2f_5y79FOFZz1A_go6m0hIUfbbAoZ0Y
79
79
  dhisana/utils/serperdev_local_business.py,sha256=JoZfTg58Hojv61cyuwA2lcnPdLT1lawnWaBNrUYWnuQ,6447
80
80
  dhisana/utils/serperdev_search.py,sha256=_iBKIfHMq4gFv5StYz58eArriygoi1zW6VnLlux8vto,9363
81
81
  dhisana/utils/smtp_email_tools.py,sha256=tF6GoNqkS9pWP52VTTrYSgL7wPdIp3XTklxrHLdzU5o,17186
82
- dhisana/utils/test_connect.py,sha256=fTJW2UzC4zbzFKk_CvJJk-hRmMXYb4XJmyGa_ja-pbA,69022
82
+ dhisana/utils/test_connect.py,sha256=aQjPIKevMF_c-wd4Te2UtPpaY-dEa9PVp6MsNCjQ7q8,83667
83
83
  dhisana/utils/trasform_json.py,sha256=7V72XNDpuxUX0GHN5D83z4anj_gIf5zabaHeQm7b1_E,6979
84
84
  dhisana/utils/web_download_parse_tools.py,sha256=ouXwH7CmjcRjoBfP5BWat86MvcGO-8rLCmWQe_eZKjc,7810
85
85
  dhisana/utils/workflow_code_model.py,sha256=YPWse5vBb3O6Km2PvKh1Q3AB8qBkzLt1CrR5xOL9Mro,99
@@ -93,8 +93,8 @@ dhisana/workflow/agent.py,sha256=esv7_i_XuMkV2j1nz_UlsHov_m6X5WZZiZm_tG4OBHU,565
93
93
  dhisana/workflow/flow.py,sha256=xWE3qQbM7j2B3FH8XnY3zOL_QXX4LbTW4ArndnEYJE0,1638
94
94
  dhisana/workflow/task.py,sha256=HlWz9mtrwLYByoSnePOemBUBrMEcj7KbgNjEE1oF5wo,1830
95
95
  dhisana/workflow/test.py,sha256=E7lRnXK0PguTNzyasHytLzTJdkqIPxG5_4qk4hMEeKc,3399
96
- dhisana-0.0.1.dev232.dist-info/METADATA,sha256=RceG6DFxX8ctp-wWTECxTC_saDy69bTzmnB1FdWyf_I,1190
97
- dhisana-0.0.1.dev232.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
98
- dhisana-0.0.1.dev232.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
99
- dhisana-0.0.1.dev232.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
100
- dhisana-0.0.1.dev232.dist-info/RECORD,,
96
+ dhisana-0.0.1.dev234.dist-info/METADATA,sha256=2DPCNFKHW9jDh68a3oNEpad87cQHbmOVxXoEOW2-TrE,1190
97
+ dhisana-0.0.1.dev234.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
98
+ dhisana-0.0.1.dev234.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
99
+ dhisana-0.0.1.dev234.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
100
+ dhisana-0.0.1.dev234.dist-info/RECORD,,