dhisana 0.0.1.dev250__py3-none-any.whl → 0.0.1.dev252__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/cache_output_tools.py +22 -2
- dhisana/utils/check_email_validity_tools.py +4 -4
- dhisana/utils/proxy_curl_tools.py +12 -9
- {dhisana-0.0.1.dev250.dist-info → dhisana-0.0.1.dev252.dist-info}/METADATA +1 -1
- {dhisana-0.0.1.dev250.dist-info → dhisana-0.0.1.dev252.dist-info}/RECORD +8 -8
- {dhisana-0.0.1.dev250.dist-info → dhisana-0.0.1.dev252.dist-info}/WHEEL +0 -0
- {dhisana-0.0.1.dev250.dist-info → dhisana-0.0.1.dev252.dist-info}/entry_points.txt +0 -0
- {dhisana-0.0.1.dev250.dist-info → dhisana-0.0.1.dev252.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import hashlib
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
+
from datetime import datetime, timezone
|
|
5
6
|
|
|
6
7
|
from azure.storage.blob import BlobServiceClient
|
|
7
8
|
from azure.core.exceptions import ResourceNotFoundError, AzureError
|
|
@@ -49,10 +50,11 @@ def cache_output(tool_name: str, key: str, value, ttl: int = None) -> bool:
|
|
|
49
50
|
# Construct the blob name using a virtual folder for the tool name
|
|
50
51
|
blob_name = f"{tool_name}/{key_hash}.json"
|
|
51
52
|
|
|
52
|
-
# Prepare the cache data
|
|
53
|
+
# Prepare the cache data with timestamp for TTL expiration checking
|
|
53
54
|
cache_data = {
|
|
54
55
|
"value": value,
|
|
55
|
-
"ttl": ttl
|
|
56
|
+
"ttl": ttl,
|
|
57
|
+
"cached_at": datetime.now(timezone.utc).isoformat()
|
|
56
58
|
}
|
|
57
59
|
data = json.dumps(cache_data)
|
|
58
60
|
|
|
@@ -88,6 +90,24 @@ def retrieve_output(tool_name: str, key: str):
|
|
|
88
90
|
download_stream = blob_client.download_blob()
|
|
89
91
|
content = download_stream.readall() # content is in bytes
|
|
90
92
|
cache_data = json.loads(content.decode("utf-8"))
|
|
93
|
+
|
|
94
|
+
# Check if TTL has expired
|
|
95
|
+
ttl = cache_data.get("ttl")
|
|
96
|
+
cached_at = cache_data.get("cached_at")
|
|
97
|
+
|
|
98
|
+
if ttl is not None and cached_at is not None:
|
|
99
|
+
try:
|
|
100
|
+
cached_time = datetime.fromisoformat(cached_at)
|
|
101
|
+
now = datetime.now(timezone.utc)
|
|
102
|
+
elapsed_seconds = (now - cached_time).total_seconds()
|
|
103
|
+
if elapsed_seconds > ttl:
|
|
104
|
+
logger.info(f"Cache expired for blob '{blob_name}' (elapsed: {elapsed_seconds}s, ttl: {ttl}s)")
|
|
105
|
+
return None
|
|
106
|
+
except (ValueError, TypeError) as e:
|
|
107
|
+
logger.warning(f"Error parsing cached_at timestamp: {e}")
|
|
108
|
+
# If we can't parse the timestamp, treat as expired for safety
|
|
109
|
+
return None
|
|
110
|
+
|
|
91
111
|
return cache_data.get("value")
|
|
92
112
|
except ResourceNotFoundError:
|
|
93
113
|
# Blob does not exist
|
|
@@ -514,8 +514,8 @@ async def guess_email_with_apollo(
|
|
|
514
514
|
if not apollo_email:
|
|
515
515
|
return {"email": "", "email_confidence": "low"}
|
|
516
516
|
|
|
517
|
-
# quick re‑check with
|
|
518
|
-
validation = await
|
|
517
|
+
# quick re‑check with ZeroBounce
|
|
518
|
+
validation = await check_email_validity_with_zero_bounce(apollo_email, tool_config)
|
|
519
519
|
conf = validation.get("confidence", "low")
|
|
520
520
|
return {"email": apollo_email, "email_confidence": conf}
|
|
521
521
|
|
|
@@ -547,7 +547,7 @@ async def check_email_validity(
|
|
|
547
547
|
return {"email": email_id, "confidence": "low", "is_valid": False}
|
|
548
548
|
|
|
549
549
|
names = [c.get("name") for c in tool_config if c.get("name")]
|
|
550
|
-
priority = ["
|
|
550
|
+
priority = ["zerobounce", "findymail", "hunter"]
|
|
551
551
|
|
|
552
552
|
result: Dict[str, Any] = {"email": email_id, "confidence": "low", "is_valid": False}
|
|
553
553
|
|
|
@@ -586,7 +586,7 @@ async def guess_email(
|
|
|
586
586
|
return {"email": "", "email_confidence": "low"}
|
|
587
587
|
|
|
588
588
|
names = [c.get("name") for c in tool_config if c.get("name")]
|
|
589
|
-
priority = ["
|
|
589
|
+
priority = ["apollo", "findymail", "hunter", "zerobounce"]
|
|
590
590
|
|
|
591
591
|
result: Dict[str, Any] = {"email": "", "email_confidence": "low"}
|
|
592
592
|
|
|
@@ -16,6 +16,9 @@ from urllib.parse import urlparse, urlunparse
|
|
|
16
16
|
logging.basicConfig(level=logging.INFO)
|
|
17
17
|
logger = logging.getLogger(__name__)
|
|
18
18
|
|
|
19
|
+
# Cache TTL for Proxycurl responses: 14 days in seconds
|
|
20
|
+
PROXYCURL_CACHE_TTL = 14 * 24 * 60 * 60 # 1,209,600 seconds
|
|
21
|
+
|
|
19
22
|
|
|
20
23
|
def get_proxycurl_access_token(tool_config: Optional[List[Dict]] = None) -> str:
|
|
21
24
|
"""
|
|
@@ -117,7 +120,7 @@ async def enrich_person_info_from_proxycurl(
|
|
|
117
120
|
if response.status == 200:
|
|
118
121
|
result = await response.json()
|
|
119
122
|
if linkedin_url:
|
|
120
|
-
cache_output("enrich_person_info_from_proxycurl", linkedin_url, result)
|
|
123
|
+
cache_output("enrich_person_info_from_proxycurl", linkedin_url, result, ttl=PROXYCURL_CACHE_TTL)
|
|
121
124
|
logger.info("Successfully retrieved person info from Proxycurl.")
|
|
122
125
|
return result
|
|
123
126
|
elif response.status == 404:
|
|
@@ -195,14 +198,14 @@ async def lookup_person_in_proxy_curl_by_name(
|
|
|
195
198
|
logger.debug(f"Received response status: {response.status}")
|
|
196
199
|
if response.status == 200:
|
|
197
200
|
result = await response.json()
|
|
198
|
-
cache_output("lookup_person_in_proxycurl_by_name", key, result)
|
|
201
|
+
cache_output("lookup_person_in_proxycurl_by_name", key, result, ttl=PROXYCURL_CACHE_TTL)
|
|
199
202
|
logger.info("Successfully retrieved person search info from Proxycurl.")
|
|
200
203
|
return result
|
|
201
204
|
elif response.status == 404:
|
|
202
205
|
msg = "Person not found"
|
|
203
206
|
logger.warning(msg)
|
|
204
207
|
if key:
|
|
205
|
-
cache_output("lookup_person_in_proxycurl_by_name", key, {'error': msg})
|
|
208
|
+
cache_output("lookup_person_in_proxycurl_by_name", key, {'error': msg}, ttl=PROXYCURL_CACHE_TTL)
|
|
206
209
|
return {'error': msg}
|
|
207
210
|
elif response.status == 429:
|
|
208
211
|
msg = "Rate limit exceeded"
|
|
@@ -415,7 +418,7 @@ async def enrich_organization_info_from_proxycurl(
|
|
|
415
418
|
if response.status == 200:
|
|
416
419
|
result = await response.json()
|
|
417
420
|
transformed_result = transform_company_data(result)
|
|
418
|
-
cache_output("enrich_organization_info_from_proxycurl", cache_key, transformed_result)
|
|
421
|
+
cache_output("enrich_organization_info_from_proxycurl", cache_key, transformed_result, ttl=PROXYCURL_CACHE_TTL)
|
|
419
422
|
logger.info("Successfully retrieved and transformed organization info from Proxycurl by LinkedIn URL.")
|
|
420
423
|
return transformed_result
|
|
421
424
|
elif response.status == 429:
|
|
@@ -429,7 +432,7 @@ async def enrich_organization_info_from_proxycurl(
|
|
|
429
432
|
f"Proxycurl organization profile not found for LinkedIn URL {standardized_url}: {error_text}"
|
|
430
433
|
)
|
|
431
434
|
cache_output(
|
|
432
|
-
"enrich_organization_info_from_proxycurl", cache_key, {}
|
|
435
|
+
"enrich_organization_info_from_proxycurl", cache_key, {}, ttl=PROXYCURL_CACHE_TTL
|
|
433
436
|
)
|
|
434
437
|
return {}
|
|
435
438
|
else:
|
|
@@ -483,7 +486,7 @@ async def enrich_organization_info_from_proxycurl(
|
|
|
483
486
|
if profile_response.status == 200:
|
|
484
487
|
result = await profile_response.json()
|
|
485
488
|
transformed_result = transform_company_data(result)
|
|
486
|
-
cache_output("enrich_organization_info_from_proxycurl", domain_cache_key, transformed_result)
|
|
489
|
+
cache_output("enrich_organization_info_from_proxycurl", domain_cache_key, transformed_result, ttl=PROXYCURL_CACHE_TTL)
|
|
487
490
|
logger.info("Successfully retrieved and transformed organization info from Proxycurl by domain.")
|
|
488
491
|
return transformed_result
|
|
489
492
|
elif profile_response.status == 429:
|
|
@@ -509,7 +512,7 @@ async def enrich_organization_info_from_proxycurl(
|
|
|
509
512
|
elif response.status == 404:
|
|
510
513
|
msg = "Item not found"
|
|
511
514
|
logger.warning(msg)
|
|
512
|
-
cache_output("enrich_organization_info_from_proxycurl", domain_cache_key, {})
|
|
515
|
+
cache_output("enrich_organization_info_from_proxycurl", domain_cache_key, {}, ttl=PROXYCURL_CACHE_TTL)
|
|
513
516
|
return {}
|
|
514
517
|
else:
|
|
515
518
|
error_text = await response.text()
|
|
@@ -572,7 +575,7 @@ async def enrich_job_info_from_proxycurl(
|
|
|
572
575
|
logger.debug(f"Received response status: {response.status}")
|
|
573
576
|
if response.status == 200:
|
|
574
577
|
result = await response.json()
|
|
575
|
-
cache_output("enrich_job_info_from_proxycurl", job_url, result)
|
|
578
|
+
cache_output("enrich_job_info_from_proxycurl", job_url, result, ttl=PROXYCURL_CACHE_TTL)
|
|
576
579
|
logger.info("Successfully retrieved job info from Proxycurl.")
|
|
577
580
|
return result
|
|
578
581
|
elif response.status == 429:
|
|
@@ -583,7 +586,7 @@ async def enrich_job_info_from_proxycurl(
|
|
|
583
586
|
elif response.status == 404:
|
|
584
587
|
msg = "Job not found"
|
|
585
588
|
logger.warning(msg)
|
|
586
|
-
cache_output("enrich_job_info_from_proxycurl", job_url, {'error': msg})
|
|
589
|
+
cache_output("enrich_job_info_from_proxycurl", job_url, {'error': msg}, ttl=PROXYCURL_CACHE_TTL)
|
|
587
590
|
return {'error': msg}
|
|
588
591
|
else:
|
|
589
592
|
error_text = await response.text()
|
|
@@ -15,9 +15,9 @@ dhisana/utils/agent_tools.py,sha256=pzBFvfhU4wfSB4zv1eiRzjmnteJnfhC5V32r_v1m38Y,
|
|
|
15
15
|
dhisana/utils/apollo_tools.py,sha256=1b9FaL_3spQKUsOP1k8-kD1kcFxCkG4KJHoN71SjOkU,69796
|
|
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
|
-
dhisana/utils/cache_output_tools.py,sha256=
|
|
18
|
+
dhisana/utils/cache_output_tools.py,sha256=q-d-WR_pkIUQyCJk8T-u9sfTy1TvvWoD2kJlZfqY-vA,4392
|
|
19
19
|
dhisana/utils/cache_output_tools_local.py,sha256=okVIY54Xs5avTLu5Sv8neEPsPBce501m-6E_UhQkCAg,2447
|
|
20
|
-
dhisana/utils/check_email_validity_tools.py,sha256=
|
|
20
|
+
dhisana/utils/check_email_validity_tools.py,sha256=EBuA4a20q3DF22PykqqI5H9KiNB70ckiihBgZm-StwM,26618
|
|
21
21
|
dhisana/utils/check_for_intent_signal.py,sha256=pC9k1_2fuUXBUxmikfxmoILlqhGMsJDVxrX0m73XQzA,4517
|
|
22
22
|
dhisana/utils/check_linkedin_url_validity.py,sha256=HoniUZ0BrtuvUmo4xLnKbxfiDBxVhatj2fJGNADtRlU,8365
|
|
23
23
|
dhisana/utils/clay_tools.py,sha256=Pi3UMcxSDz2pd2Xq_tn9G8Zot5DUQM_cYNgWI2478EM,1282
|
|
@@ -62,7 +62,7 @@ dhisana/utils/openai_helpers.py,sha256=ZK9S5-jcLCpiiD6XBLkCqYcNz-AGYmO9xh4e2H-FD
|
|
|
62
62
|
dhisana/utils/openapi_spec_to_tools.py,sha256=oBLVq3WeDWvW9O02NCvY8bxQURQdKwHJHGcX8bC_b2I,1926
|
|
63
63
|
dhisana/utils/parse_linkedin_messages_txt.py,sha256=g3N_ac70mAEuDDQ7Ott6mkOaBwI3ZvcsJD3R9RlYwPQ,3320
|
|
64
64
|
dhisana/utils/profile.py,sha256=12IhefaLp3j74zzBzVRe50_KWqtWZ_cdzUKlYNy9T2Y,1192
|
|
65
|
-
dhisana/utils/proxy_curl_tools.py,sha256=
|
|
65
|
+
dhisana/utils/proxy_curl_tools.py,sha256=3i7Qpk0POME5OU5-lHQ6BlnOi88tIZl-Z0oMrphnCFQ,52975
|
|
66
66
|
dhisana/utils/proxycurl_search_leads.py,sha256=6PlraPNYQ4fIDzTYnY-T2g_ip5fPkqHigbGoPD8ZosQ,16131
|
|
67
67
|
dhisana/utils/python_function_to_tools.py,sha256=jypddM6WTlIQmRWnqAugYJXvaPYaXaMgWAZRYeeGlj4,2682
|
|
68
68
|
dhisana/utils/research_lead.py,sha256=L6w2fK5in8z2xmWnXBjbkvTdrwPf8ZfvAXq3gb7-S6s,7009
|
|
@@ -95,8 +95,8 @@ dhisana/workflow/agent.py,sha256=esv7_i_XuMkV2j1nz_UlsHov_m6X5WZZiZm_tG4OBHU,565
|
|
|
95
95
|
dhisana/workflow/flow.py,sha256=xWE3qQbM7j2B3FH8XnY3zOL_QXX4LbTW4ArndnEYJE0,1638
|
|
96
96
|
dhisana/workflow/task.py,sha256=HlWz9mtrwLYByoSnePOemBUBrMEcj7KbgNjEE1oF5wo,1830
|
|
97
97
|
dhisana/workflow/test.py,sha256=E7lRnXK0PguTNzyasHytLzTJdkqIPxG5_4qk4hMEeKc,3399
|
|
98
|
-
dhisana-0.0.1.
|
|
99
|
-
dhisana-0.0.1.
|
|
100
|
-
dhisana-0.0.1.
|
|
101
|
-
dhisana-0.0.1.
|
|
102
|
-
dhisana-0.0.1.
|
|
98
|
+
dhisana-0.0.1.dev252.dist-info/METADATA,sha256=-JTN_wbJlVSnuz7HWr4sETgjQZuhaXFhZrFIJkKhQ28,1190
|
|
99
|
+
dhisana-0.0.1.dev252.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
100
|
+
dhisana-0.0.1.dev252.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
|
|
101
|
+
dhisana-0.0.1.dev252.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
|
|
102
|
+
dhisana-0.0.1.dev252.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|