dhisana 0.0.1.dev219__py3-none-any.whl → 0.0.1.dev220__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.
- dhisana/utils/apollo_tools.py +90 -39
- {dhisana-0.0.1.dev219.dist-info → dhisana-0.0.1.dev220.dist-info}/METADATA +1 -1
- {dhisana-0.0.1.dev219.dist-info → dhisana-0.0.1.dev220.dist-info}/RECORD +6 -6
- {dhisana-0.0.1.dev219.dist-info → dhisana-0.0.1.dev220.dist-info}/WHEEL +0 -0
- {dhisana-0.0.1.dev219.dist-info → dhisana-0.0.1.dev220.dist-info}/entry_points.txt +0 -0
- {dhisana-0.0.1.dev219.dist-info → dhisana-0.0.1.dev220.dist-info}/top_level.txt +0 -0
dhisana/utils/apollo_tools.py
CHANGED
|
@@ -11,7 +11,7 @@ from dhisana.schemas.sales import LeadsQueryFilters, CompanyQueryFilters
|
|
|
11
11
|
from dhisana.utils.cache_output_tools import cache_output, retrieve_output
|
|
12
12
|
from dhisana.utils.assistant_tool_tag import assistant_tool
|
|
13
13
|
from urllib.parse import urlparse, parse_qs
|
|
14
|
-
from typing import Any, Dict, List, Optional, Union
|
|
14
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
15
15
|
|
|
16
16
|
from dhisana.utils.clean_properties import cleanup_properties
|
|
17
17
|
|
|
@@ -19,50 +19,81 @@ logging.basicConfig(level=logging.INFO)
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def get_apollo_access_token(tool_config: Optional[List[Dict]] = None) -> str:
|
|
22
|
+
def get_apollo_access_token(tool_config: Optional[List[Dict]] = None) -> Tuple[str, bool]:
|
|
23
23
|
"""
|
|
24
|
-
Retrieves
|
|
24
|
+
Retrieves an Apollo access token from tool configuration or environment variables.
|
|
25
25
|
|
|
26
26
|
Args:
|
|
27
|
-
tool_config (list):
|
|
28
|
-
Each dictionary should have a "name" key and a "configuration" key,
|
|
29
|
-
where "configuration" is a list of dictionaries containing "name" and "value" keys.
|
|
27
|
+
tool_config (list): Optional tool configuration payload provided to the tool.
|
|
30
28
|
|
|
31
29
|
Returns:
|
|
32
|
-
str:
|
|
30
|
+
Tuple[str, bool]: A tuple containing the token string and a boolean flag indicating
|
|
31
|
+
whether the token represents an OAuth bearer token (``True``) or an API key (``False``).
|
|
33
32
|
|
|
34
33
|
Raises:
|
|
35
34
|
ValueError: If the Apollo integration has not been configured.
|
|
36
35
|
"""
|
|
37
|
-
|
|
36
|
+
token: Optional[str] = None
|
|
37
|
+
is_oauth = False
|
|
38
38
|
|
|
39
39
|
if tool_config:
|
|
40
|
-
logger.debug(f"Tool config provided: {tool_config}")
|
|
41
40
|
apollo_config = next(
|
|
42
41
|
(item for item in tool_config if item.get("name") == "apollo"), None
|
|
43
42
|
)
|
|
44
43
|
if apollo_config:
|
|
45
44
|
config_map = {
|
|
46
|
-
item["name"]: item
|
|
45
|
+
item["name"]: item.get("value")
|
|
47
46
|
for item in apollo_config.get("configuration", [])
|
|
48
47
|
if item
|
|
49
48
|
}
|
|
50
|
-
|
|
49
|
+
|
|
50
|
+
raw_oauth = config_map.get("oauth_tokens")
|
|
51
|
+
if isinstance(raw_oauth, str):
|
|
52
|
+
try:
|
|
53
|
+
raw_oauth = json.loads(raw_oauth)
|
|
54
|
+
except Exception:
|
|
55
|
+
raw_oauth = None
|
|
56
|
+
if isinstance(raw_oauth, dict):
|
|
57
|
+
token = (
|
|
58
|
+
raw_oauth.get("access_token")
|
|
59
|
+
or raw_oauth.get("token")
|
|
60
|
+
)
|
|
61
|
+
if token:
|
|
62
|
+
is_oauth = True
|
|
63
|
+
|
|
64
|
+
if not token:
|
|
65
|
+
direct_access_token = config_map.get("access_token")
|
|
66
|
+
if direct_access_token:
|
|
67
|
+
token = direct_access_token
|
|
68
|
+
is_oauth = True
|
|
69
|
+
|
|
70
|
+
if not token:
|
|
71
|
+
api_key = config_map.get("apiKey") or config_map.get("api_key")
|
|
72
|
+
if api_key:
|
|
73
|
+
token = api_key
|
|
74
|
+
is_oauth = False
|
|
51
75
|
else:
|
|
52
76
|
logger.warning("No 'apollo' config item found in tool_config.")
|
|
53
|
-
else:
|
|
54
|
-
logger.debug("No tool_config provided or it's None.")
|
|
55
77
|
|
|
56
|
-
|
|
57
|
-
|
|
78
|
+
if not token:
|
|
79
|
+
env_oauth_token = os.getenv("APOLLO_ACCESS_TOKEN")
|
|
80
|
+
if env_oauth_token:
|
|
81
|
+
token = env_oauth_token
|
|
82
|
+
is_oauth = True
|
|
83
|
+
|
|
84
|
+
if not token:
|
|
85
|
+
env_api_key = os.getenv("APOLLO_API_KEY")
|
|
86
|
+
if env_api_key:
|
|
87
|
+
token = env_api_key
|
|
88
|
+
is_oauth = False
|
|
58
89
|
|
|
59
|
-
if not
|
|
90
|
+
if not token:
|
|
60
91
|
logger.error("Apollo integration is not configured.")
|
|
61
92
|
raise ValueError(
|
|
62
93
|
"Apollo integration is not configured. Please configure the connection to Apollo in Integrations."
|
|
63
94
|
)
|
|
64
95
|
|
|
65
|
-
return
|
|
96
|
+
return token, is_oauth
|
|
66
97
|
|
|
67
98
|
|
|
68
99
|
@assistant_tool
|
|
@@ -94,16 +125,17 @@ async def enrich_person_info_from_apollo(
|
|
|
94
125
|
"""
|
|
95
126
|
logger.info("Entering enrich_person_info_from_apollo")
|
|
96
127
|
|
|
97
|
-
|
|
128
|
+
token, is_oauth = get_apollo_access_token(tool_config)
|
|
98
129
|
|
|
99
130
|
if not linkedin_url and not email and not phone:
|
|
100
131
|
logger.warning("No linkedin_url, email, or phone provided. At least one is required.")
|
|
101
132
|
return {'error': "At least one of linkedin_url, email, or phone must be provided"}
|
|
102
133
|
|
|
103
|
-
headers = {
|
|
104
|
-
|
|
105
|
-
"
|
|
106
|
-
|
|
134
|
+
headers = {"Content-Type": "application/json"}
|
|
135
|
+
if is_oauth:
|
|
136
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
137
|
+
else:
|
|
138
|
+
headers["X-Api-Key"] = token
|
|
107
139
|
|
|
108
140
|
data = {}
|
|
109
141
|
if linkedin_url:
|
|
@@ -186,11 +218,12 @@ async def lookup_person_in_apollo_by_name(
|
|
|
186
218
|
logger.warning("No full_name provided.")
|
|
187
219
|
return {'error': "Full name is required"}
|
|
188
220
|
|
|
189
|
-
|
|
190
|
-
headers = {
|
|
191
|
-
|
|
192
|
-
"
|
|
193
|
-
|
|
221
|
+
token, is_oauth = get_apollo_access_token(tool_config)
|
|
222
|
+
headers = {"Content-Type": "application/json"}
|
|
223
|
+
if is_oauth:
|
|
224
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
225
|
+
else:
|
|
226
|
+
headers["X-Api-Key"] = token
|
|
194
227
|
|
|
195
228
|
# Construct the query payload
|
|
196
229
|
data = {
|
|
@@ -263,18 +296,21 @@ async def enrich_organization_info_from_apollo(
|
|
|
263
296
|
"""
|
|
264
297
|
logger.info("Entering enrich_organization_info_from_apollo")
|
|
265
298
|
|
|
266
|
-
|
|
299
|
+
token, is_oauth = get_apollo_access_token(tool_config)
|
|
267
300
|
|
|
268
301
|
if not organization_domain:
|
|
269
302
|
logger.warning("No organization domain provided.")
|
|
270
303
|
return {'error': "organization domain must be provided"}
|
|
271
304
|
|
|
272
305
|
headers = {
|
|
273
|
-
"X-Api-Key": f"{APOLLO_API_KEY}",
|
|
274
306
|
"Content-Type": "application/json",
|
|
275
307
|
"Cache-Control": "no-cache",
|
|
276
308
|
"accept": "application/json"
|
|
277
309
|
}
|
|
310
|
+
if is_oauth:
|
|
311
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
312
|
+
else:
|
|
313
|
+
headers["X-Api-Key"] = token
|
|
278
314
|
|
|
279
315
|
cached_response = retrieve_output("enrich_organization_info_from_apollo", organization_domain)
|
|
280
316
|
if cached_response is not None:
|
|
@@ -364,12 +400,15 @@ async def search_people_with_apollo(
|
|
|
364
400
|
logger.warning("No payload given; returning empty result.")
|
|
365
401
|
return []
|
|
366
402
|
|
|
367
|
-
|
|
403
|
+
token, is_oauth = get_apollo_access_token(tool_config)
|
|
368
404
|
headers = {
|
|
369
405
|
"Cache-Control": "no-cache",
|
|
370
406
|
"Content-Type": "application/json",
|
|
371
|
-
"X-Api-Key": api_key,
|
|
372
407
|
}
|
|
408
|
+
if is_oauth:
|
|
409
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
410
|
+
else:
|
|
411
|
+
headers["X-Api-Key"] = token
|
|
373
412
|
|
|
374
413
|
url = "https://api.apollo.io/api/v1/mixed_people/search"
|
|
375
414
|
logger.info(f"Sending payload to Apollo (single page): {json.dumps(dynamic_payload, indent=2)}")
|
|
@@ -840,12 +879,15 @@ async def search_leads_with_apollo_page(
|
|
|
840
879
|
f" Payload: {json.dumps(page_payload, indent=2)}")
|
|
841
880
|
|
|
842
881
|
# Get the full Apollo API response with pagination metadata
|
|
843
|
-
|
|
882
|
+
token, is_oauth = get_apollo_access_token(tool_config)
|
|
844
883
|
headers = {
|
|
845
884
|
"Cache-Control": "no-cache",
|
|
846
885
|
"Content-Type": "application/json",
|
|
847
|
-
"X-Api-Key": api_key,
|
|
848
886
|
}
|
|
887
|
+
if is_oauth:
|
|
888
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
889
|
+
else:
|
|
890
|
+
headers["X-Api-Key"] = token
|
|
849
891
|
|
|
850
892
|
url = "https://api.apollo.io/api/v1/mixed_people/search"
|
|
851
893
|
|
|
@@ -950,17 +992,20 @@ async def get_organization_details_from_apollo(
|
|
|
950
992
|
"""
|
|
951
993
|
logger.info("Entering get_organization_details_from_apollo")
|
|
952
994
|
|
|
953
|
-
|
|
995
|
+
token, is_oauth = get_apollo_access_token(tool_config)
|
|
954
996
|
if not organization_id:
|
|
955
997
|
logger.warning("No organization_id provided.")
|
|
956
998
|
return {'error': "Organization ID must be provided"}
|
|
957
999
|
|
|
958
1000
|
headers = {
|
|
959
|
-
"X-Api-Key": APOLLO_API_KEY,
|
|
960
1001
|
"Content-Type": "application/json",
|
|
961
1002
|
"Cache-Control": "no-cache",
|
|
962
1003
|
"Accept": "application/json"
|
|
963
1004
|
}
|
|
1005
|
+
if is_oauth:
|
|
1006
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
1007
|
+
else:
|
|
1008
|
+
headers["X-Api-Key"] = token
|
|
964
1009
|
|
|
965
1010
|
cached_response = retrieve_output("get_organization_details_from_apollo", organization_id)
|
|
966
1011
|
if cached_response is not None:
|
|
@@ -1202,12 +1247,15 @@ async def search_companies_with_apollo(
|
|
|
1202
1247
|
logger.warning("No payload given; returning empty result.")
|
|
1203
1248
|
return []
|
|
1204
1249
|
|
|
1205
|
-
|
|
1250
|
+
token, is_oauth = get_apollo_access_token(tool_config)
|
|
1206
1251
|
headers = {
|
|
1207
1252
|
"Cache-Control": "no-cache",
|
|
1208
1253
|
"Content-Type": "application/json",
|
|
1209
|
-
"X-Api-Key": api_key,
|
|
1210
1254
|
}
|
|
1255
|
+
if is_oauth:
|
|
1256
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
1257
|
+
else:
|
|
1258
|
+
headers["X-Api-Key"] = token
|
|
1211
1259
|
|
|
1212
1260
|
url = "https://api.apollo.io/api/v1/organizations/search"
|
|
1213
1261
|
logger.info(f"Sending payload to Apollo organizations endpoint (single page): {json.dumps(dynamic_payload, indent=2)}")
|
|
@@ -1508,12 +1556,15 @@ async def search_companies_with_apollo_page(
|
|
|
1508
1556
|
f" Payload: {json.dumps(cleaned_payload, indent=2)}")
|
|
1509
1557
|
|
|
1510
1558
|
# Get the full Apollo API response with pagination metadata
|
|
1511
|
-
|
|
1559
|
+
token, is_oauth = get_apollo_access_token(tool_config)
|
|
1512
1560
|
headers = {
|
|
1513
1561
|
"Cache-Control": "no-cache",
|
|
1514
1562
|
"Content-Type": "application/json",
|
|
1515
|
-
"X-Api-Key": api_key,
|
|
1516
1563
|
}
|
|
1564
|
+
if is_oauth:
|
|
1565
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
1566
|
+
else:
|
|
1567
|
+
headers["X-Api-Key"] = token
|
|
1517
1568
|
|
|
1518
1569
|
url = "https://api.apollo.io/api/v1/organizations/search"
|
|
1519
1570
|
|
|
@@ -12,7 +12,7 @@ dhisana/ui/components.py,sha256=4NXrAyl9tx2wWwoVYyABO-EOGnreGMvql1AkXWajIIo,1431
|
|
|
12
12
|
dhisana/utils/__init__.py,sha256=jv2YF__bseklT3OWEzlqJ5qE24c4aWd5F4r0TTjOrWQ,65
|
|
13
13
|
dhisana/utils/add_mapping.py,sha256=oq_QNqag86DhgdwINBRRXNx7SOb8Q9M-V0QLP6pTzr8,13837
|
|
14
14
|
dhisana/utils/agent_tools.py,sha256=pzBFvfhU4wfSB4zv1eiRzjmnteJnfhC5V32r_v1m38Y,2321
|
|
15
|
-
dhisana/utils/apollo_tools.py,sha256=
|
|
15
|
+
dhisana/utils/apollo_tools.py,sha256=WSt5SV3ElfYlNjFw6-8FyZ0_6wete5vahoSYPhACcD8,65716
|
|
16
16
|
dhisana/utils/assistant_tool_tag.py,sha256=rYRl8ubLI7fUUIjg30XTefHBkFgRqNEVC12lF6U6Z-8,119
|
|
17
17
|
dhisana/utils/built_with_api_tools.py,sha256=TFNGhnPb2vFdveVCpjiCvE1WKe_eK95UPpR0Ha5NgMQ,10260
|
|
18
18
|
dhisana/utils/cache_output_tools.py,sha256=sSAruvUZn-WAJQ0lB9T1QjSmkm-_14AuxC9xKmcCQ0k,3428
|
|
@@ -92,8 +92,8 @@ dhisana/workflow/agent.py,sha256=esv7_i_XuMkV2j1nz_UlsHov_m6X5WZZiZm_tG4OBHU,565
|
|
|
92
92
|
dhisana/workflow/flow.py,sha256=xWE3qQbM7j2B3FH8XnY3zOL_QXX4LbTW4ArndnEYJE0,1638
|
|
93
93
|
dhisana/workflow/task.py,sha256=HlWz9mtrwLYByoSnePOemBUBrMEcj7KbgNjEE1oF5wo,1830
|
|
94
94
|
dhisana/workflow/test.py,sha256=kwW8jWqSBNcRmoyaxlTuZCMOpGJpTbJQgHI7gSjwdzM,3399
|
|
95
|
-
dhisana-0.0.1.
|
|
96
|
-
dhisana-0.0.1.
|
|
97
|
-
dhisana-0.0.1.
|
|
98
|
-
dhisana-0.0.1.
|
|
99
|
-
dhisana-0.0.1.
|
|
95
|
+
dhisana-0.0.1.dev220.dist-info/METADATA,sha256=HsH4PGLIF-9i_HFv9ODch9lhyl7tdQ48epFKP7TcUXM,1190
|
|
96
|
+
dhisana-0.0.1.dev220.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
97
|
+
dhisana-0.0.1.dev220.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
|
|
98
|
+
dhisana-0.0.1.dev220.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
|
|
99
|
+
dhisana-0.0.1.dev220.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|