dhisana 0.0.1.dev231__tar.gz → 0.0.1.dev257__tar.gz
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-0.0.1.dev231 → dhisana-0.0.1.dev257}/PKG-INFO +1 -1
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/setup.py +1 -1
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/schemas/common.py +4 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/schemas/sales.py +34 -4
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/apollo_tools.py +226 -82
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/cache_output_tools.py +22 -2
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_email_validity_tools.py +4 -4
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/enrich_lead_information.py +18 -2
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_content.py +3 -1
- dhisana-0.0.1.dev257/src/dhisana/utils/generate_custom_message.py +271 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_email.py +60 -17
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_email_response.py +132 -117
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/google_oauth_tools.py +94 -42
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/google_workspace_tools.py +120 -46
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/mailgun_tools.py +6 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/mailreach_tools.py +123 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/microsoft365_tools.py +51 -3
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/proxy_curl_tools.py +88 -21
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/sendgrid_tools.py +10 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serpapi_search_tools.py +2 -2
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/smtp_email_tools.py +109 -10
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/test_connect.py +546 -3
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/PKG-INFO +1 -1
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/SOURCES.txt +3 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_apollo_company_search.py +70 -26
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_apollo_lead_search.py +11 -3
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_connectivity.py +16 -0
- dhisana-0.0.1.dev257/tests/test_mailreach.py +179 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/README.md +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/pyproject.toml +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/setup.cfg +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/__init__.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/cli/__init__.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/cli/cli.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/cli/datasets.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/cli/models.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/cli/predictions.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/schemas/__init__.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/ui/__init__.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/ui/components.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/__init__.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/add_mapping.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/agent_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/assistant_tool_tag.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/built_with_api_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/cache_output_tools_local.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_for_intent_signal.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_linkedin_url_validity.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/clay_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/clean_properties.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/company_utils.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_salesnav_query.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_search_query.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/composite_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/dataframe_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/domain_parser.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/email_body_utils.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/email_parse_helpers.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/email_provider.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/fetch_openai_config.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/field_validators.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/g2_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_flow.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_linkedin_connect_message.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_linkedin_response_message.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_structured_output_internal.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/google_custom_search.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/hubspot_clearbit.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/hubspot_crm_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/instantly_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/linkedin_crawler.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/lusha_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/openai_assistant_and_file_utils.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/openai_helpers.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/profile.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/proxycurl_search_leads.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/python_function_to_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/research_lead.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/search_router.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/search_router_jobs.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serarch_router_local_business.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serpapi_additional_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serpapi_google_jobs.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serpapi_google_search.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serpapi_local_business_search.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serperdev_google_jobs.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serperdev_local_business.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/serperdev_search.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/trasform_json.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/web_download_parse_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/workflow_code_model.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/zoominfo_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/workflow/__init__.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/workflow/agent.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/workflow/flow.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/workflow/task.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/workflow/test.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/dependency_links.txt +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/entry_points.txt +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/requires.txt +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/top_level.txt +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_agent_tools.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_email_body_utils.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_google_document.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_hubspot_call_logs.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_linkedin_serper.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_mcp_connectivity.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_proxycurl_get_company_search_id.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_proxycurl_job_count.py +0 -0
- {dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/tests/test_structured_output_with_mcp.py +0 -0
|
@@ -378,6 +378,8 @@ class SendEmailContext(BaseModel):
|
|
|
378
378
|
sender_email: str
|
|
379
379
|
labels: Optional[List[str]]
|
|
380
380
|
body_format: BodyFormat = BodyFormat.AUTO
|
|
381
|
+
headers: Optional[Dict[str, str]] = None
|
|
382
|
+
email_open_token: Optional[str] = None
|
|
381
383
|
|
|
382
384
|
class QueryEmailContext(BaseModel):
|
|
383
385
|
start_time: str
|
|
@@ -392,6 +394,8 @@ class ReplyEmailContext(BaseModel):
|
|
|
392
394
|
reply_body: str
|
|
393
395
|
sender_email: str
|
|
394
396
|
sender_name: str
|
|
397
|
+
headers: Optional[Dict[str, str]] = None
|
|
398
|
+
fallback_recipient: Optional[str] = None
|
|
395
399
|
mark_as_read: str = "True"
|
|
396
400
|
add_labels: Optional[List[str]] = None
|
|
397
401
|
reply_body_format: BodyFormat = BodyFormat.AUTO
|
|
@@ -270,6 +270,7 @@ class ChannelType(str, Enum):
|
|
|
270
270
|
LINKEDIN_CONNECT_MESSAGE = "linkedin_connect_message"
|
|
271
271
|
REPLY_EMAIL = "reply_email"
|
|
272
272
|
LINKEDIN_USER_MESSAGE = "linkedin_user_message"
|
|
273
|
+
CUSTOM_MESSAGE = "custom_message"
|
|
273
274
|
|
|
274
275
|
class SenderInfo(BaseModel):
|
|
275
276
|
"""
|
|
@@ -291,10 +292,14 @@ class MessageGenerationInstructions(BaseModel):
|
|
|
291
292
|
Holds the user-supplied instructions for generating the message:
|
|
292
293
|
- instructions_to_generate_message: Plain text or template instructions from the user.
|
|
293
294
|
- prompt_engineering_guidance: (Optional) Extra guidelines for structuring the prompt.
|
|
295
|
+
- allow_html: Whether HTML output is allowed.
|
|
296
|
+
- html_template: Optional HTML scaffolding or guidance.
|
|
294
297
|
"""
|
|
295
298
|
instructions_to_generate_message: Optional[str] = None
|
|
296
299
|
prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
|
|
297
300
|
use_cache: Optional[bool] = True
|
|
301
|
+
allow_html: Optional[bool] = False
|
|
302
|
+
html_template: Optional[str] = None
|
|
298
303
|
|
|
299
304
|
class CampaignContext(BaseModel):
|
|
300
305
|
"""
|
|
@@ -723,7 +728,10 @@ class LeadsQueryFilters(BaseModel):
|
|
|
723
728
|
# CHANGED: Renamed to be more descriptive
|
|
724
729
|
industries: Optional[List[str]] = Field(
|
|
725
730
|
default=None,
|
|
726
|
-
description=
|
|
731
|
+
description=(
|
|
732
|
+
"List of organization industries (case sensitive). "
|
|
733
|
+
"Maps to organization_industries in Apollo."
|
|
734
|
+
)
|
|
727
735
|
)
|
|
728
736
|
|
|
729
737
|
# Potential existing fields
|
|
@@ -749,7 +757,7 @@ class LeadsQueryFilters(BaseModel):
|
|
|
749
757
|
# CHANGED: Renamed to be more descriptive
|
|
750
758
|
company_domains: Optional[List[str]] = Field(
|
|
751
759
|
default=None,
|
|
752
|
-
description="Domains of the person's employer (e.g., ['microsoft.com']). Maps to
|
|
760
|
+
description="Domains of the person's employer (e.g., ['apollo.io', 'microsoft.com']). Maps to q_organization_domains_list in Apollo API. Accepts up to 1,000 domains. Do not include www. or @ symbol."
|
|
753
761
|
)
|
|
754
762
|
|
|
755
763
|
# CHANGED: Renamed to be more descriptive
|
|
@@ -795,7 +803,20 @@ class LeadsQueryFilters(BaseModel):
|
|
|
795
803
|
# CHANGED: Renamed for consistency
|
|
796
804
|
company_industry_tag_ids: Optional[List[str]] = Field(
|
|
797
805
|
default=None,
|
|
798
|
-
description=
|
|
806
|
+
description=(
|
|
807
|
+
"List of industry tag IDs, e.g. ['5567cd4773696439b10b0000']. "
|
|
808
|
+
"Maps to organization_industry_tag_ids."
|
|
809
|
+
)
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
q_organization_keyword_tags: Optional[List[str]] = Field(
|
|
813
|
+
default=None,
|
|
814
|
+
description="Organization Keyword tags to search by"
|
|
815
|
+
)
|
|
816
|
+
|
|
817
|
+
q_not_organization_keyword_tags: Optional[List[str]] = Field(
|
|
818
|
+
default=None,
|
|
819
|
+
description="Organization Keyword tags to search by"
|
|
799
820
|
)
|
|
800
821
|
|
|
801
822
|
q_organization_search_list_id: Optional[str] = Field(
|
|
@@ -861,6 +882,16 @@ class CompanyQueryFilters(BaseModel):
|
|
|
861
882
|
default=None,
|
|
862
883
|
description="List of industry tag IDs, e.g. ['5567cd4773696439b10b0000']."
|
|
863
884
|
)
|
|
885
|
+
|
|
886
|
+
q_organization_keyword_tags: Optional[List[str]] = Field(
|
|
887
|
+
default=None,
|
|
888
|
+
description="Organization Keyword tags to search by"
|
|
889
|
+
)
|
|
890
|
+
|
|
891
|
+
q_not_organization_keyword_tags: Optional[List[str]] = Field(
|
|
892
|
+
default=None,
|
|
893
|
+
description="Organization Keyword tags to search by"
|
|
894
|
+
)
|
|
864
895
|
|
|
865
896
|
# Revenue filters
|
|
866
897
|
revenue_range_min: Optional[int] = Field(
|
|
@@ -938,4 +969,3 @@ class CompanyQueryFilters(BaseModel):
|
|
|
938
969
|
default=None,
|
|
939
970
|
description="Maximum founding year for the organization."
|
|
940
971
|
)
|
|
941
|
-
|
|
@@ -547,8 +547,10 @@ async def search_leads_with_apollo(
|
|
|
547
547
|
"revenueRange[max]": "revenue_range_max",
|
|
548
548
|
"revenueRange[min]": "revenue_range_min",
|
|
549
549
|
"currentlyUsingAnyOfTechnologyUids": "currently_using_any_of_technology_uids",
|
|
550
|
+
"organizationIndustries": "organization_industries",
|
|
550
551
|
"organizationIndustryTagIds": "organization_industry_tag_ids",
|
|
551
552
|
"notOrganizationIds": "not_organization_ids",
|
|
553
|
+
"qOrganizationDomainsList": "q_organization_domains_list",
|
|
552
554
|
}
|
|
553
555
|
|
|
554
556
|
for raw_key, raw_value_list in query_params.items():
|
|
@@ -606,13 +608,15 @@ async def search_leads_with_apollo(
|
|
|
606
608
|
"person_titles",
|
|
607
609
|
"person_seniorities",
|
|
608
610
|
"organization_locations",
|
|
609
|
-
"
|
|
611
|
+
"q_organization_domains_list",
|
|
610
612
|
"contact_email_status",
|
|
611
613
|
"organization_ids",
|
|
612
614
|
"organization_num_employees_ranges",
|
|
613
615
|
"person_not_titles", # <--- added so single item is forced into list
|
|
614
616
|
"q_organization_job_titles",
|
|
615
617
|
"organization_latest_funding_stage_cd",
|
|
618
|
+
"organization_industries",
|
|
619
|
+
"organization_industry_tag_ids",
|
|
616
620
|
):
|
|
617
621
|
if isinstance(final_value, str):
|
|
618
622
|
final_value = [final_value]
|
|
@@ -631,17 +635,28 @@ async def search_leads_with_apollo(
|
|
|
631
635
|
# -----------------------------------
|
|
632
636
|
else:
|
|
633
637
|
dynamic_payload = {
|
|
634
|
-
"person_titles": query.person_current_titles or [],
|
|
635
|
-
"person_locations": query.person_locations or [],
|
|
636
|
-
"search_signal_ids": query.filter_by_signals or [],
|
|
637
|
-
"q_keywords": query.search_keywords or "",
|
|
638
|
-
"organization_num_employees_ranges": (
|
|
639
|
-
query.organization_num_employees_ranges
|
|
640
|
-
or [f"{query.min_employees_in_organization or 1},{query.max_employees_in_organization or 1000}"]
|
|
641
|
-
),
|
|
642
638
|
"page": 1,
|
|
643
639
|
"per_page": min(max_items, 100),
|
|
644
640
|
}
|
|
641
|
+
|
|
642
|
+
# Only add fields if they have values (don't pass empty defaults)
|
|
643
|
+
if query.person_current_titles:
|
|
644
|
+
dynamic_payload["person_titles"] = query.person_current_titles
|
|
645
|
+
if query.person_locations:
|
|
646
|
+
dynamic_payload["person_locations"] = query.person_locations
|
|
647
|
+
if query.filter_by_signals:
|
|
648
|
+
dynamic_payload["search_signal_ids"] = query.filter_by_signals
|
|
649
|
+
if query.search_keywords:
|
|
650
|
+
dynamic_payload["q_keywords"] = query.search_keywords
|
|
651
|
+
|
|
652
|
+
# Only add employee ranges if explicitly provided
|
|
653
|
+
if query.organization_num_employees_ranges:
|
|
654
|
+
dynamic_payload["organization_num_employees_ranges"] = query.organization_num_employees_ranges
|
|
655
|
+
elif query.min_employees_in_organization is not None or query.max_employees_in_organization is not None:
|
|
656
|
+
min_emp = query.min_employees_in_organization or 1
|
|
657
|
+
max_emp = query.max_employees_in_organization or 1000000
|
|
658
|
+
dynamic_payload["organization_num_employees_ranges"] = [f"{min_emp},{max_emp}"]
|
|
659
|
+
|
|
645
660
|
if query.job_openings_with_titles:
|
|
646
661
|
dynamic_payload["q_organization_job_titles"] = query.job_openings_with_titles
|
|
647
662
|
if query.latest_funding_stages:
|
|
@@ -650,6 +665,15 @@ async def search_leads_with_apollo(
|
|
|
650
665
|
dynamic_payload["sort_by_field"] = query.sort_by_field
|
|
651
666
|
if query.sort_ascending is not None:
|
|
652
667
|
dynamic_payload["sort_ascending"] = query.sort_ascending
|
|
668
|
+
if query.person_seniorities:
|
|
669
|
+
dynamic_payload["person_seniorities"] = query.person_seniorities
|
|
670
|
+
if query.industries:
|
|
671
|
+
dynamic_payload["organization_industries"] = query.industries
|
|
672
|
+
if query.company_industry_tag_ids:
|
|
673
|
+
dynamic_payload["organization_industry_tag_ids"] = query.company_industry_tag_ids
|
|
674
|
+
# Add company domains to include in search
|
|
675
|
+
if query.company_domains:
|
|
676
|
+
dynamic_payload["q_organization_domains_list"] = query.company_domains
|
|
653
677
|
|
|
654
678
|
# -----------------------------
|
|
655
679
|
# C) Fetch multiple pages
|
|
@@ -765,8 +789,10 @@ async def search_leads_with_apollo_page(
|
|
|
765
789
|
"revenueRange[max]": "revenue_range_max",
|
|
766
790
|
"revenueRange[min]": "revenue_range_min",
|
|
767
791
|
"currentlyUsingAnyOfTechnologyUids": "currently_using_any_of_technology_uids",
|
|
792
|
+
"organizationIndustries": "organization_industries",
|
|
768
793
|
"organizationIndustryTagIds": "organization_industry_tag_ids",
|
|
769
794
|
"notOrganizationIds": "not_organization_ids",
|
|
795
|
+
"qOrganizationDomainsList": "q_organization_domains_list",
|
|
770
796
|
}
|
|
771
797
|
|
|
772
798
|
for raw_key, raw_value_list in query_params.items():
|
|
@@ -809,13 +835,15 @@ async def search_leads_with_apollo_page(
|
|
|
809
835
|
"person_titles",
|
|
810
836
|
"person_seniorities",
|
|
811
837
|
"organization_locations",
|
|
812
|
-
"
|
|
838
|
+
"q_organization_domains_list",
|
|
813
839
|
"contact_email_status",
|
|
814
840
|
"organization_ids",
|
|
815
841
|
"organization_num_employees_ranges",
|
|
816
842
|
"person_not_titles",
|
|
817
843
|
"q_organization_job_titles",
|
|
818
844
|
"organization_latest_funding_stage_cd",
|
|
845
|
+
"organization_industries",
|
|
846
|
+
"organization_industry_tag_ids",
|
|
819
847
|
):
|
|
820
848
|
if isinstance(final_value, str):
|
|
821
849
|
final_value = [final_value]
|
|
@@ -829,16 +857,26 @@ async def search_leads_with_apollo_page(
|
|
|
829
857
|
# B) No example_url -> build from `query`
|
|
830
858
|
# -----------------------------------
|
|
831
859
|
else:
|
|
832
|
-
dynamic_payload = {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
"
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
860
|
+
dynamic_payload = {}
|
|
861
|
+
|
|
862
|
+
# Only add fields if they have values (don't pass empty defaults)
|
|
863
|
+
if query.person_current_titles:
|
|
864
|
+
dynamic_payload["person_titles"] = query.person_current_titles
|
|
865
|
+
if query.person_locations:
|
|
866
|
+
dynamic_payload["person_locations"] = query.person_locations
|
|
867
|
+
if query.filter_by_signals:
|
|
868
|
+
dynamic_payload["search_signal_ids"] = query.filter_by_signals
|
|
869
|
+
if query.search_keywords:
|
|
870
|
+
dynamic_payload["q_keywords"] = query.search_keywords
|
|
871
|
+
|
|
872
|
+
# Only add employee ranges if explicitly provided
|
|
873
|
+
if query.organization_num_employees_ranges:
|
|
874
|
+
dynamic_payload["organization_num_employees_ranges"] = query.organization_num_employees_ranges
|
|
875
|
+
elif query.min_employees_in_organization is not None or query.max_employees_in_organization is not None:
|
|
876
|
+
min_emp = query.min_employees_in_organization or 1
|
|
877
|
+
max_emp = query.max_employees_in_organization or 1000000
|
|
878
|
+
dynamic_payload["organization_num_employees_ranges"] = [f"{min_emp},{max_emp}"]
|
|
879
|
+
|
|
842
880
|
if query.job_openings_with_titles:
|
|
843
881
|
dynamic_payload["q_organization_job_titles"] = query.job_openings_with_titles
|
|
844
882
|
if query.latest_funding_stages:
|
|
@@ -847,6 +885,19 @@ async def search_leads_with_apollo_page(
|
|
|
847
885
|
dynamic_payload["sort_by_field"] = query.sort_by_field
|
|
848
886
|
if query.sort_ascending is not None:
|
|
849
887
|
dynamic_payload["sort_ascending"] = query.sort_ascending
|
|
888
|
+
if query.q_organization_keyword_tags:
|
|
889
|
+
dynamic_payload["q_organization_keyword_tags"] = query.q_organization_keyword_tags
|
|
890
|
+
|
|
891
|
+
if query.q_not_organization_keyword_tags:
|
|
892
|
+
dynamic_payload["q_not_organization_keyword_tags"] = query.q_not_organization_keyword_tags
|
|
893
|
+
if query.industries:
|
|
894
|
+
dynamic_payload["organization_industries"] = query.industries
|
|
895
|
+
if query.company_industry_tag_ids:
|
|
896
|
+
dynamic_payload["organization_industry_tag_ids"] = query.company_industry_tag_ids
|
|
897
|
+
|
|
898
|
+
# Add company domains to include in search (Apollo API: q_organization_domains_list[])
|
|
899
|
+
if query.company_domains:
|
|
900
|
+
dynamic_payload["q_organization_domains_list"] = query.company_domains
|
|
850
901
|
|
|
851
902
|
page_payload = dict(dynamic_payload)
|
|
852
903
|
page_payload["page"] = page
|
|
@@ -1250,62 +1301,131 @@ def fill_in_company_properties(company_data: dict) -> dict:
|
|
|
1250
1301
|
company_data: Raw company data from Apollo API
|
|
1251
1302
|
|
|
1252
1303
|
Returns:
|
|
1253
|
-
Dictionary
|
|
1304
|
+
Dictionary matching the SmartList `Account` schema shape.
|
|
1254
1305
|
"""
|
|
1255
|
-
|
|
1306
|
+
def _parse_keywords(value: Any) -> List[Any]:
|
|
1307
|
+
if value is None:
|
|
1308
|
+
return []
|
|
1309
|
+
if isinstance(value, list):
|
|
1310
|
+
return value
|
|
1311
|
+
if isinstance(value, str):
|
|
1312
|
+
text = value.strip()
|
|
1313
|
+
if not text:
|
|
1314
|
+
return []
|
|
1315
|
+
if "," in text:
|
|
1316
|
+
return [part.strip() for part in text.split(",") if part.strip()]
|
|
1317
|
+
return [text]
|
|
1318
|
+
return [value]
|
|
1319
|
+
|
|
1320
|
+
def _parse_compact_number(value: Any) -> Optional[float]:
|
|
1321
|
+
if value is None:
|
|
1322
|
+
return None
|
|
1323
|
+
if isinstance(value, (int, float)):
|
|
1324
|
+
return float(value)
|
|
1325
|
+
text = str(value).strip()
|
|
1326
|
+
if not text:
|
|
1327
|
+
return None
|
|
1328
|
+
text = text.replace("$", "").replace(",", "").strip()
|
|
1329
|
+
multiplier = 1.0
|
|
1330
|
+
suffix = text[-1:].upper()
|
|
1331
|
+
if suffix in ("K", "M", "B"):
|
|
1332
|
+
multiplier = {"K": 1e3, "M": 1e6, "B": 1e9}[suffix]
|
|
1333
|
+
text = text[:-1].strip()
|
|
1334
|
+
try:
|
|
1335
|
+
return float(text) * multiplier
|
|
1336
|
+
except ValueError:
|
|
1337
|
+
return None
|
|
1256
1338
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1339
|
+
annual_revenue = (
|
|
1340
|
+
company_data.get("organization_revenue")
|
|
1341
|
+
if company_data.get("organization_revenue") is not None
|
|
1342
|
+
else company_data.get("annual_revenue")
|
|
1343
|
+
)
|
|
1344
|
+
annual_revenue = _parse_compact_number(annual_revenue)
|
|
1345
|
+
if annual_revenue is None:
|
|
1346
|
+
annual_revenue = _parse_compact_number(company_data.get("organization_revenue_printed"))
|
|
1347
|
+
|
|
1348
|
+
company_size = company_data.get("estimated_num_employees")
|
|
1349
|
+
if company_size is not None:
|
|
1350
|
+
try:
|
|
1351
|
+
company_size = int(company_size)
|
|
1352
|
+
except (TypeError, ValueError):
|
|
1353
|
+
company_size = None
|
|
1354
|
+
|
|
1355
|
+
founded_year = company_data.get("founded_year")
|
|
1356
|
+
if founded_year is not None:
|
|
1357
|
+
try:
|
|
1358
|
+
founded_year = int(founded_year)
|
|
1359
|
+
except (TypeError, ValueError):
|
|
1360
|
+
founded_year = None
|
|
1361
|
+
|
|
1362
|
+
primary_phone = company_data.get("primary_phone")
|
|
1363
|
+
primary_phone_number = None
|
|
1364
|
+
if isinstance(primary_phone, dict):
|
|
1365
|
+
primary_phone_number = primary_phone.get("number") or primary_phone.get(
|
|
1366
|
+
"sanitized_number"
|
|
1367
|
+
)
|
|
1368
|
+
|
|
1369
|
+
phone = (
|
|
1370
|
+
primary_phone_number
|
|
1371
|
+
or company_data.get("phone")
|
|
1372
|
+
or company_data.get("primary_phone_number")
|
|
1373
|
+
or company_data.get("sanitized_phone")
|
|
1374
|
+
)
|
|
1375
|
+
|
|
1376
|
+
industry = company_data.get("industry")
|
|
1377
|
+
if not industry and isinstance(company_data.get("industries"), list):
|
|
1378
|
+
industries = [str(x).strip() for x in company_data["industries"] if str(x).strip()]
|
|
1379
|
+
industry = industries[0] if industries else None
|
|
1380
|
+
|
|
1381
|
+
billing_street = (
|
|
1382
|
+
company_data.get("street_address")
|
|
1383
|
+
or company_data.get("billing_street")
|
|
1384
|
+
or company_data.get("address")
|
|
1385
|
+
or company_data.get("raw_address")
|
|
1386
|
+
)
|
|
1387
|
+
|
|
1388
|
+
account: Dict[str, Any] = {
|
|
1389
|
+
"name": company_data.get("name"),
|
|
1390
|
+
"domain": company_data.get("primary_domain"),
|
|
1391
|
+
"website": company_data.get("website_url"),
|
|
1392
|
+
"phone": phone,
|
|
1393
|
+
"fax": company_data.get("fax") or company_data.get("fax_number"),
|
|
1394
|
+
"industry": industry,
|
|
1395
|
+
"company_size": company_size,
|
|
1396
|
+
"founded_year": founded_year,
|
|
1397
|
+
"annual_revenue": annual_revenue,
|
|
1398
|
+
"type": company_data.get("type") or company_data.get("organization_type"),
|
|
1399
|
+
"ownership": company_data.get("ownership"),
|
|
1400
|
+
"organization_linkedin_url": company_data.get("linkedin_url"),
|
|
1401
|
+
"billing_street": billing_street,
|
|
1402
|
+
"billing_city": company_data.get("city"),
|
|
1403
|
+
"billing_state": company_data.get("state"),
|
|
1404
|
+
"billing_zip": company_data.get("postal_code")
|
|
1405
|
+
or company_data.get("zip")
|
|
1406
|
+
or company_data.get("zipcode"),
|
|
1407
|
+
"billing_country": company_data.get("country"),
|
|
1408
|
+
"description": company_data.get("description"),
|
|
1409
|
+
"keywords": _parse_keywords(company_data.get("keywords")),
|
|
1410
|
+
"tags": [],
|
|
1411
|
+
"notes": [],
|
|
1412
|
+
"additional_properties": {
|
|
1413
|
+
"apollo_organization_id": company_data.get("id"),
|
|
1414
|
+
"facebook_url": company_data.get("facebook_url"),
|
|
1415
|
+
"twitter_url": company_data.get("twitter_url"),
|
|
1416
|
+
"funding_stage": company_data.get("latest_funding_stage"),
|
|
1417
|
+
"total_funding": company_data.get("total_funding"),
|
|
1418
|
+
"technology_names": company_data.get("technology_names"),
|
|
1419
|
+
"primary_phone": primary_phone if isinstance(primary_phone, dict) else None,
|
|
1420
|
+
"raw_address": company_data.get("raw_address"),
|
|
1421
|
+
"organization_revenue_printed": company_data.get("organization_revenue_printed"),
|
|
1422
|
+
"apollo_organization_data": json.dumps(cleanup_properties(company_data)),
|
|
1423
|
+
},
|
|
1424
|
+
"research_summary": None,
|
|
1425
|
+
"enchrichment_status": None,
|
|
1306
1426
|
}
|
|
1307
1427
|
|
|
1308
|
-
return
|
|
1428
|
+
return account
|
|
1309
1429
|
|
|
1310
1430
|
|
|
1311
1431
|
@assistant_tool
|
|
@@ -1363,7 +1483,7 @@ async def search_companies_with_apollo_page(
|
|
|
1363
1483
|
"organizationIndustries": "organization_industries",
|
|
1364
1484
|
"organizationIndustryTagIds": "organization_industry_tag_ids",
|
|
1365
1485
|
"qKeywords": "q_keywords",
|
|
1366
|
-
"
|
|
1486
|
+
"qOrganizationDomainsList": "q_organization_domains_list",
|
|
1367
1487
|
"sortAscending": "sort_ascending",
|
|
1368
1488
|
"sortByField": "sort_by_field",
|
|
1369
1489
|
"organizationLatestFundingStageCd": "organization_latest_funding_stage_cd",
|
|
@@ -1427,7 +1547,7 @@ async def search_companies_with_apollo_page(
|
|
|
1427
1547
|
"organization_locations",
|
|
1428
1548
|
"organization_industries",
|
|
1429
1549
|
"organization_industry_tag_ids",
|
|
1430
|
-
"
|
|
1550
|
+
"q_organization_domains_list",
|
|
1431
1551
|
"q_organization_keyword_tags",
|
|
1432
1552
|
"organization_ids",
|
|
1433
1553
|
"not_organization_ids",
|
|
@@ -1448,7 +1568,7 @@ async def search_companies_with_apollo_page(
|
|
|
1448
1568
|
# -----------------------------------
|
|
1449
1569
|
else:
|
|
1450
1570
|
dynamic_payload = {}
|
|
1451
|
-
|
|
1571
|
+
|
|
1452
1572
|
# Only add fields if they have values (Apollo doesn't like empty arrays)
|
|
1453
1573
|
if query.organization_locations:
|
|
1454
1574
|
dynamic_payload["organization_locations"] = query.organization_locations
|
|
@@ -1468,15 +1588,39 @@ async def search_companies_with_apollo_page(
|
|
|
1468
1588
|
dynamic_payload["organization_num_employees_ranges"] = employee_ranges
|
|
1469
1589
|
|
|
1470
1590
|
# Add optional parameters only if they have values
|
|
1591
|
+
def _normalize_string_list(value: Any) -> List[str]:
|
|
1592
|
+
if value is None:
|
|
1593
|
+
return []
|
|
1594
|
+
if isinstance(value, str):
|
|
1595
|
+
return [part.strip() for part in value.split(",") if part.strip()]
|
|
1596
|
+
if isinstance(value, list):
|
|
1597
|
+
normalized: List[str] = []
|
|
1598
|
+
for item in value:
|
|
1599
|
+
if item is None:
|
|
1600
|
+
continue
|
|
1601
|
+
text = str(item).strip()
|
|
1602
|
+
if not text:
|
|
1603
|
+
continue
|
|
1604
|
+
normalized.extend([part.strip() for part in text.split(",") if part.strip()])
|
|
1605
|
+
return normalized
|
|
1606
|
+
text = str(value).strip()
|
|
1607
|
+
return [text] if text else []
|
|
1608
|
+
|
|
1471
1609
|
if query.q_keywords:
|
|
1472
|
-
|
|
1473
|
-
if
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1610
|
+
keywords = _normalize_string_list(query.q_keywords)
|
|
1611
|
+
if keywords:
|
|
1612
|
+
dynamic_payload["q_keywords"] = " ".join(keywords)
|
|
1613
|
+
|
|
1614
|
+
org_keyword_tags = _normalize_string_list(query.q_organization_keyword_tags)
|
|
1615
|
+
if org_keyword_tags:
|
|
1616
|
+
dynamic_payload["q_organization_keyword_tags"] = org_keyword_tags
|
|
1617
|
+
|
|
1618
|
+
not_org_keyword_tags = _normalize_string_list(query.q_not_organization_keyword_tags)
|
|
1619
|
+
if not_org_keyword_tags:
|
|
1620
|
+
dynamic_payload["q_not_organization_keyword_tags"] = not_org_keyword_tags
|
|
1621
|
+
|
|
1478
1622
|
if query.q_organization_domains:
|
|
1479
|
-
dynamic_payload["
|
|
1623
|
+
dynamic_payload["q_organization_domains_list"] = query.q_organization_domains
|
|
1480
1624
|
if query.revenue_range_min is not None:
|
|
1481
1625
|
dynamic_payload["revenue_range_min"] = query.revenue_range_min
|
|
1482
1626
|
if query.revenue_range_max is not None:
|
|
@@ -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
|
{dhisana-0.0.1.dev231 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_email_validity_tools.py
RENAMED
|
@@ -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
|
|
|
@@ -765,16 +765,32 @@ async def enrich_organization_info_from_company_url(
|
|
|
765
765
|
organization_linkedin_url: str,
|
|
766
766
|
use_strict_check: bool = True,
|
|
767
767
|
tool_config: Optional[List[Dict[str, Any]]] = None,
|
|
768
|
+
categories: Optional[bool] = None,
|
|
769
|
+
funding_data: Optional[bool] = None,
|
|
770
|
+
exit_data: Optional[bool] = None,
|
|
771
|
+
acquisitions: Optional[bool] = None,
|
|
772
|
+
extra: Optional[bool] = None,
|
|
773
|
+
use_cache: Optional[str] = "if-present",
|
|
774
|
+
fallback_to_cache: Optional[str] = "on-error",
|
|
768
775
|
) -> Dict[str, Any]:
|
|
769
776
|
"""
|
|
770
777
|
Given an organization LinkedIn URL, attempt to enrich its data (e.g. name, website)
|
|
771
|
-
via ProxyCurl.
|
|
778
|
+
via ProxyCurl. Additional Proxycurl Company API boolean flags (categories, funding_data, etc.)
|
|
779
|
+
can be supplied to control the returned payload (True -> "include"). If data is found,
|
|
780
|
+
set domain, then return the dict. Otherwise, return {}.
|
|
772
781
|
"""
|
|
773
782
|
|
|
774
783
|
# Call ProxyCurl to enrich
|
|
775
784
|
company_data = await enrich_organization_info_from_proxycurl(
|
|
776
785
|
organization_linkedin_url=organization_linkedin_url,
|
|
777
|
-
tool_config=tool_config
|
|
786
|
+
tool_config=tool_config,
|
|
787
|
+
categories=categories,
|
|
788
|
+
funding_data=funding_data,
|
|
789
|
+
exit_data=exit_data,
|
|
790
|
+
acquisitions=acquisitions,
|
|
791
|
+
extra=extra,
|
|
792
|
+
use_cache=use_cache,
|
|
793
|
+
fallback_to_cache=fallback_to_cache,
|
|
778
794
|
)
|
|
779
795
|
|
|
780
796
|
# If ProxyCurl returned any data, set domain, then return
|