dhisana 0.0.1.dev116__py3-none-any.whl → 0.0.1.dev236__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/schemas/common.py +10 -1
- dhisana/schemas/sales.py +203 -22
- dhisana/utils/add_mapping.py +0 -2
- dhisana/utils/apollo_tools.py +739 -119
- dhisana/utils/built_with_api_tools.py +4 -2
- dhisana/utils/check_email_validity_tools.py +35 -18
- dhisana/utils/check_for_intent_signal.py +1 -2
- dhisana/utils/check_linkedin_url_validity.py +34 -8
- dhisana/utils/clay_tools.py +3 -2
- dhisana/utils/clean_properties.py +1 -4
- dhisana/utils/compose_salesnav_query.py +0 -1
- dhisana/utils/compose_search_query.py +7 -3
- dhisana/utils/composite_tools.py +0 -1
- dhisana/utils/dataframe_tools.py +2 -2
- dhisana/utils/email_body_utils.py +72 -0
- dhisana/utils/email_provider.py +174 -35
- dhisana/utils/enrich_lead_information.py +183 -53
- dhisana/utils/fetch_openai_config.py +129 -0
- dhisana/utils/field_validators.py +1 -1
- dhisana/utils/g2_tools.py +0 -1
- dhisana/utils/generate_content.py +0 -1
- dhisana/utils/generate_email.py +68 -23
- dhisana/utils/generate_email_response.py +294 -46
- dhisana/utils/generate_flow.py +0 -1
- dhisana/utils/generate_linkedin_connect_message.py +9 -2
- dhisana/utils/generate_linkedin_response_message.py +137 -66
- dhisana/utils/generate_structured_output_internal.py +317 -164
- dhisana/utils/google_custom_search.py +150 -44
- dhisana/utils/google_oauth_tools.py +721 -0
- dhisana/utils/google_workspace_tools.py +278 -54
- dhisana/utils/hubspot_clearbit.py +3 -1
- dhisana/utils/hubspot_crm_tools.py +718 -272
- dhisana/utils/instantly_tools.py +3 -1
- dhisana/utils/lusha_tools.py +10 -7
- dhisana/utils/mailgun_tools.py +150 -0
- dhisana/utils/microsoft365_tools.py +447 -0
- dhisana/utils/openai_assistant_and_file_utils.py +121 -177
- dhisana/utils/openai_helpers.py +8 -6
- dhisana/utils/parse_linkedin_messages_txt.py +1 -3
- dhisana/utils/profile.py +37 -0
- dhisana/utils/proxy_curl_tools.py +377 -76
- dhisana/utils/proxycurl_search_leads.py +426 -0
- dhisana/utils/research_lead.py +3 -3
- dhisana/utils/sales_navigator_crawler.py +1 -6
- dhisana/utils/salesforce_crm_tools.py +323 -50
- dhisana/utils/search_router.py +131 -0
- dhisana/utils/search_router_jobs.py +51 -0
- dhisana/utils/sendgrid_tools.py +126 -91
- dhisana/utils/serarch_router_local_business.py +75 -0
- dhisana/utils/serpapi_additional_tools.py +290 -0
- dhisana/utils/serpapi_google_jobs.py +117 -0
- dhisana/utils/serpapi_google_search.py +188 -0
- dhisana/utils/serpapi_local_business_search.py +129 -0
- dhisana/utils/serpapi_search_tools.py +360 -432
- dhisana/utils/serperdev_google_jobs.py +125 -0
- dhisana/utils/serperdev_local_business.py +154 -0
- dhisana/utils/serperdev_search.py +233 -0
- dhisana/utils/smtp_email_tools.py +178 -18
- dhisana/utils/test_connect.py +1603 -130
- dhisana/utils/trasform_json.py +3 -3
- dhisana/utils/web_download_parse_tools.py +0 -1
- dhisana/utils/zoominfo_tools.py +2 -3
- dhisana/workflow/test.py +1 -1
- {dhisana-0.0.1.dev116.dist-info → dhisana-0.0.1.dev236.dist-info}/METADATA +1 -1
- dhisana-0.0.1.dev236.dist-info/RECORD +100 -0
- {dhisana-0.0.1.dev116.dist-info → dhisana-0.0.1.dev236.dist-info}/WHEEL +1 -1
- dhisana-0.0.1.dev116.dist-info/RECORD +0 -83
- {dhisana-0.0.1.dev116.dist-info → dhisana-0.0.1.dev236.dist-info}/entry_points.txt +0 -0
- {dhisana-0.0.1.dev116.dist-info → dhisana-0.0.1.dev236.dist-info}/top_level.txt +0 -0
dhisana/schemas/common.py
CHANGED
|
@@ -364,6 +364,12 @@ class Integration(IntegrationBase):
|
|
|
364
364
|
Integration.model_rebuild()
|
|
365
365
|
IntegrationUpdate.model_rebuild()
|
|
366
366
|
|
|
367
|
+
class BodyFormat(str, Enum):
|
|
368
|
+
AUTO = "auto"
|
|
369
|
+
HTML = "html"
|
|
370
|
+
TEXT = "text"
|
|
371
|
+
|
|
372
|
+
|
|
367
373
|
class SendEmailContext(BaseModel):
|
|
368
374
|
recipient: str
|
|
369
375
|
subject: str
|
|
@@ -371,6 +377,7 @@ class SendEmailContext(BaseModel):
|
|
|
371
377
|
sender_name: str
|
|
372
378
|
sender_email: str
|
|
373
379
|
labels: Optional[List[str]]
|
|
380
|
+
body_format: BodyFormat = BodyFormat.AUTO
|
|
374
381
|
|
|
375
382
|
class QueryEmailContext(BaseModel):
|
|
376
383
|
start_time: str
|
|
@@ -385,5 +392,7 @@ class ReplyEmailContext(BaseModel):
|
|
|
385
392
|
reply_body: str
|
|
386
393
|
sender_email: str
|
|
387
394
|
sender_name: str
|
|
395
|
+
fallback_recipient: Optional[str] = None
|
|
388
396
|
mark_as_read: str = "True"
|
|
389
|
-
add_labels: Optional[List[str]] = None
|
|
397
|
+
add_labels: Optional[List[str]] = None
|
|
398
|
+
reply_body_format: BodyFormat = BodyFormat.AUTO
|
dhisana/schemas/sales.py
CHANGED
|
@@ -1,24 +1,31 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
1
3
|
from uuid import UUID
|
|
2
|
-
from pydantic import BaseModel, Field
|
|
4
|
+
from pydantic import BaseModel, Field, field_validator
|
|
3
5
|
from typing import List, Optional, Dict, Any
|
|
4
6
|
from enum import Enum
|
|
5
7
|
from typing import Optional, List, Dict, Literal
|
|
6
8
|
|
|
7
|
-
from dhisana.schemas.common import User
|
|
8
9
|
|
|
9
10
|
# -----------------------------
|
|
10
11
|
# Lead-List-Specific Schemas
|
|
11
12
|
# -----------------------------
|
|
12
13
|
|
|
13
14
|
class Lead(BaseModel):
|
|
14
|
-
id: Optional[
|
|
15
|
+
id: Optional[UUID] = None
|
|
15
16
|
full_name: Optional[str] = None
|
|
16
17
|
first_name: Optional[str] = None
|
|
17
18
|
last_name: Optional[str] = None
|
|
18
19
|
email: Optional[str] = None
|
|
19
20
|
user_linkedin_url: Optional[str] = None
|
|
20
21
|
user_linkedin_salesnav_url: Optional[str] = None
|
|
22
|
+
organization_linkedin_url: Optional[str] = None
|
|
23
|
+
organization_linkedin_salesnav_url: Optional[str] = None
|
|
24
|
+
linkedin_follower_count: Optional[int] = None
|
|
21
25
|
primary_domain_of_organization: Optional[str] = None
|
|
26
|
+
twitter_handle: Optional[str] = None
|
|
27
|
+
twitch_handle: Optional[str] = None
|
|
28
|
+
github_handle: Optional[str] = None
|
|
22
29
|
job_title: Optional[str] = None
|
|
23
30
|
phone: Optional[str] = None
|
|
24
31
|
headline: Optional[str] = None
|
|
@@ -26,25 +33,69 @@ class Lead(BaseModel):
|
|
|
26
33
|
organization_name: Optional[str] = None
|
|
27
34
|
organization_website: Optional[str] = None
|
|
28
35
|
summary_about_lead: Optional[str] = None
|
|
36
|
+
|
|
37
|
+
qualification_score: Optional[float] = None
|
|
38
|
+
qualification_reason: Optional[str] = None
|
|
39
|
+
revenue: Optional[str] = None
|
|
40
|
+
company_size: Optional[str] = None
|
|
41
|
+
industry: Optional[str] = None
|
|
42
|
+
|
|
43
|
+
keywords: Optional[Any] = None
|
|
44
|
+
tags: List[str] = []
|
|
45
|
+
notes: List[str] = []
|
|
46
|
+
additional_properties: Optional[Dict[str, Any]] = {}
|
|
29
47
|
workflow_stage: Optional[str] = None
|
|
30
|
-
|
|
31
|
-
engaged:
|
|
48
|
+
|
|
49
|
+
engaged: bool = False
|
|
32
50
|
last_contact: Optional[int] = None
|
|
33
|
-
additional_properties: Optional[Dict[str, str]] = None
|
|
34
51
|
research_summary: Optional[str] = None
|
|
35
52
|
task_ids: Optional[List[str]] = None
|
|
36
|
-
email_validation_status: Optional[
|
|
37
|
-
|
|
38
|
-
] = None
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
email_validation_status: Optional[str] = None
|
|
54
|
+
linkedin_validation_status: Optional[str] = None
|
|
55
|
+
research_status: Optional[str] = None
|
|
56
|
+
enchrichment_status: Optional[str] = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@field_validator("linkedin_follower_count", mode="before")
|
|
60
|
+
@classmethod
|
|
61
|
+
def parse_linkedin_follower_count(cls, v):
|
|
62
|
+
if v is None or v == "":
|
|
63
|
+
return None
|
|
64
|
+
if isinstance(v, str):
|
|
65
|
+
v = v.strip()
|
|
66
|
+
if v == "":
|
|
67
|
+
return None
|
|
68
|
+
try:
|
|
69
|
+
return int(v)
|
|
70
|
+
except ValueError:
|
|
71
|
+
raise ValueError("linkedin_follower_count must be an integer")
|
|
72
|
+
return v
|
|
73
|
+
|
|
74
|
+
@field_validator("notes", mode="before")
|
|
75
|
+
@classmethod
|
|
76
|
+
def ensure_notes_list(cls, v):
|
|
77
|
+
"""Coerce notes to a list of strings.
|
|
78
|
+
Handles legacy cases where the DB may contain a scalar or JSON string.
|
|
79
|
+
"""
|
|
80
|
+
if v is None:
|
|
81
|
+
return []
|
|
82
|
+
if isinstance(v, list):
|
|
83
|
+
# Ensure all elements are strings
|
|
84
|
+
return [str(item) if not isinstance(item, str) else item for item in v]
|
|
85
|
+
if isinstance(v, str):
|
|
86
|
+
# Try to parse JSON array; if not, wrap as single-note list
|
|
87
|
+
try:
|
|
88
|
+
parsed = json.loads(v)
|
|
89
|
+
if isinstance(parsed, list):
|
|
90
|
+
return [str(item) if not isinstance(item, str) else item for item in parsed]
|
|
91
|
+
except Exception:
|
|
92
|
+
pass
|
|
93
|
+
return [v]
|
|
94
|
+
# Fallback: wrap any other scalar/object as a single string entry
|
|
95
|
+
try:
|
|
96
|
+
return [json.dumps(v)]
|
|
97
|
+
except Exception:
|
|
98
|
+
return [str(v)]
|
|
48
99
|
|
|
49
100
|
|
|
50
101
|
class LeadList(BaseModel):
|
|
@@ -240,9 +291,14 @@ class MessageGenerationInstructions(BaseModel):
|
|
|
240
291
|
Holds the user-supplied instructions for generating the message:
|
|
241
292
|
- instructions_to_generate_message: Plain text or template instructions from the user.
|
|
242
293
|
- prompt_engineering_guidance: (Optional) Extra guidelines for structuring the prompt.
|
|
294
|
+
- allow_html: Whether HTML output is allowed.
|
|
295
|
+
- html_template: Optional HTML scaffolding or guidance.
|
|
243
296
|
"""
|
|
244
297
|
instructions_to_generate_message: Optional[str] = None
|
|
245
298
|
prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
|
|
299
|
+
use_cache: Optional[bool] = True
|
|
300
|
+
allow_html: Optional[bool] = False
|
|
301
|
+
html_template: Optional[str] = None
|
|
246
302
|
|
|
247
303
|
class CampaignContext(BaseModel):
|
|
248
304
|
"""
|
|
@@ -304,6 +360,7 @@ class MessageItem(BaseModel):
|
|
|
304
360
|
...,
|
|
305
361
|
description="Body of the message in plain text"
|
|
306
362
|
)
|
|
363
|
+
html_body: Optional[str] = None
|
|
307
364
|
|
|
308
365
|
class MessageResponse(BaseModel):
|
|
309
366
|
"""
|
|
@@ -439,14 +496,14 @@ class HubSpotLeadInformation(BaseModel):
|
|
|
439
496
|
organization_name: str = Field("", description="Current Company where lead works")
|
|
440
497
|
organization_website: str = Field("", description="Current Company website of the lead")
|
|
441
498
|
organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
|
|
442
|
-
additional_properties: Optional[Dict[str,
|
|
499
|
+
additional_properties: Optional[Dict[str, Any]] = None
|
|
443
500
|
|
|
444
501
|
class HubSpotCompanyinformation(BaseModel):
|
|
445
502
|
primary_domain_of_organization: str = Field("", description="Primary domain of the organization")
|
|
446
503
|
organization_name: str = Field("", description="Current Company where lead works")
|
|
447
504
|
organization_website: str = Field("", description="Current Company website of the lead")
|
|
448
505
|
organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
|
|
449
|
-
additional_properties: Optional[Dict[str,
|
|
506
|
+
additional_properties: Optional[Dict[str, Any]] = None
|
|
450
507
|
|
|
451
508
|
|
|
452
509
|
# --------------------------------------------------------------------
|
|
@@ -463,6 +520,7 @@ HUBSPOT_TO_LEAD_MAPPING = {
|
|
|
463
520
|
"address": "lead_location", # You can choose "city", "state", etc. if you prefer
|
|
464
521
|
"city": "lead_location",
|
|
465
522
|
"domain": "primary_domain_of_organization",
|
|
523
|
+
"hs_linkedin_url": "user_linkedin_url",
|
|
466
524
|
}
|
|
467
525
|
|
|
468
526
|
class SmartListStatus(str, Enum):
|
|
@@ -483,6 +541,11 @@ class SmartListSourceType(str, Enum):
|
|
|
483
541
|
GOOGLE_SHEETS = "GOOGLE_SHEETS"
|
|
484
542
|
CUSTOM_WEBSITE = "CUSTOM_WEBSITE"
|
|
485
543
|
GITHUB = "GITHUB"
|
|
544
|
+
ICP_SEARCH = "ICP_SEARCH"
|
|
545
|
+
LOCAL_BUSINESS = "LOCAL_BUSINESS"
|
|
546
|
+
GOOGLE_JOBS = "GOOGLE_JOBS"
|
|
547
|
+
WEBHOOK = "WEBHOOK"
|
|
548
|
+
GOOGLE_CUSTOM_SITE_SEARCH = "GOOGLE_CUSTOM_SITE_SEARCH"
|
|
486
549
|
|
|
487
550
|
class SourceConfiguration(BaseModel):
|
|
488
551
|
"""
|
|
@@ -578,13 +641,18 @@ class SmartListLead(BaseModel):
|
|
|
578
641
|
organization_name: Optional[str] = None
|
|
579
642
|
organization_website: Optional[str] = None
|
|
580
643
|
summary_about_lead: Optional[str] = None
|
|
581
|
-
keywords: Optional[
|
|
644
|
+
keywords: Optional[Any] = None
|
|
582
645
|
additional_properties: Optional[Dict[str, Any]] = None
|
|
583
646
|
research_summary: Optional[str] = None
|
|
584
647
|
|
|
585
648
|
qualification_score: Optional[float] = None
|
|
586
649
|
qualification_reason: Optional[str] = None
|
|
587
650
|
source: Optional[str] = None
|
|
651
|
+
|
|
652
|
+
email_validation_status: Optional[str] = None
|
|
653
|
+
linkedin_validation_status: Optional[str] = None
|
|
654
|
+
research_status: Optional[str] = None
|
|
655
|
+
enchrichment_status: Optional[str] = None
|
|
588
656
|
|
|
589
657
|
agent_instance_id: Optional[UUID] = None
|
|
590
658
|
organization_id: Optional[UUID] = None
|
|
@@ -596,7 +664,6 @@ class SmartListLead(BaseModel):
|
|
|
596
664
|
revenue: Optional[str] = None
|
|
597
665
|
company_size: Optional[str] = None
|
|
598
666
|
industry: Optional[str] = None
|
|
599
|
-
|
|
600
667
|
class Config:
|
|
601
668
|
from_attributes = True
|
|
602
669
|
|
|
@@ -761,3 +828,117 @@ class LeadsQueryFilters(BaseModel):
|
|
|
761
828
|
description="Ranges for organization number of employees."
|
|
762
829
|
)
|
|
763
830
|
|
|
831
|
+
|
|
832
|
+
class CompanyQueryFilters(BaseModel):
|
|
833
|
+
"""
|
|
834
|
+
Defines the filter parameters for querying companies/organizations in the Apollo database.
|
|
835
|
+
All fields are optional and default to None if not specified by user.
|
|
836
|
+
"""
|
|
837
|
+
|
|
838
|
+
# Core company search parameters
|
|
839
|
+
organization_locations: Optional[List[str]] = Field(
|
|
840
|
+
default=None,
|
|
841
|
+
description="List of organization headquarters locations (city, state, country)."
|
|
842
|
+
)
|
|
843
|
+
|
|
844
|
+
organization_num_employees_ranges: Optional[List[str]] = Field(
|
|
845
|
+
default=None,
|
|
846
|
+
description="Employee count ranges, e.g. ['1,10', '11,50', '51,200']. Use specific ranges."
|
|
847
|
+
)
|
|
848
|
+
|
|
849
|
+
min_employees: Optional[int] = Field(
|
|
850
|
+
default=None,
|
|
851
|
+
description="Minimum number of employees (>=1). Internally converted to a numeric range."
|
|
852
|
+
)
|
|
853
|
+
|
|
854
|
+
max_employees: Optional[int] = Field(
|
|
855
|
+
default=None,
|
|
856
|
+
description="Maximum number of employees (<=100000). Internally converted to a numeric range."
|
|
857
|
+
)
|
|
858
|
+
|
|
859
|
+
organization_industries: Optional[List[str]] = Field(
|
|
860
|
+
default=None,
|
|
861
|
+
description="List of organization industries."
|
|
862
|
+
)
|
|
863
|
+
|
|
864
|
+
organization_industry_tag_ids: Optional[List[str]] = Field(
|
|
865
|
+
default=None,
|
|
866
|
+
description="List of industry tag IDs, e.g. ['5567cd4773696439b10b0000']."
|
|
867
|
+
)
|
|
868
|
+
|
|
869
|
+
# Revenue filters
|
|
870
|
+
revenue_range_min: Optional[int] = Field(
|
|
871
|
+
default=None,
|
|
872
|
+
description="Minimum company revenue in USD."
|
|
873
|
+
)
|
|
874
|
+
|
|
875
|
+
revenue_range_max: Optional[int] = Field(
|
|
876
|
+
default=None,
|
|
877
|
+
description="Maximum company revenue in USD."
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
# Funding and growth
|
|
881
|
+
organization_latest_funding_stage_cd: Optional[List[str]] = Field(
|
|
882
|
+
default=None,
|
|
883
|
+
description="List of funding stage codes, e.g. ['2', '3', '10']."
|
|
884
|
+
)
|
|
885
|
+
|
|
886
|
+
# Technology and keywords
|
|
887
|
+
currently_using_any_of_technology_uids: Optional[List[str]] = Field(
|
|
888
|
+
default=None,
|
|
889
|
+
description="Technology UIDs used by the organization, e.g. ['google_font_api']."
|
|
890
|
+
)
|
|
891
|
+
|
|
892
|
+
q_keywords: Optional[str] = Field(
|
|
893
|
+
default=None,
|
|
894
|
+
description="Keywords to search for in company descriptions, names, etc."
|
|
895
|
+
)
|
|
896
|
+
|
|
897
|
+
q_organization_domains: Optional[List[str]] = Field(
|
|
898
|
+
default=None,
|
|
899
|
+
description="Specific company domains to search for, e.g. ['microsoft.com', 'google.com']."
|
|
900
|
+
)
|
|
901
|
+
|
|
902
|
+
# Company-specific filters
|
|
903
|
+
organization_ids: Optional[List[str]] = Field(
|
|
904
|
+
default=None,
|
|
905
|
+
description="Specific Apollo organization IDs to include."
|
|
906
|
+
)
|
|
907
|
+
|
|
908
|
+
not_organization_ids: Optional[List[str]] = Field(
|
|
909
|
+
default=None,
|
|
910
|
+
description="Apollo organization IDs to exclude from results."
|
|
911
|
+
)
|
|
912
|
+
|
|
913
|
+
# Search lists
|
|
914
|
+
q_organization_search_list_id: Optional[str] = Field(
|
|
915
|
+
default=None,
|
|
916
|
+
description="Include only organizations in a specific search list."
|
|
917
|
+
)
|
|
918
|
+
|
|
919
|
+
q_not_organization_search_list_id: Optional[str] = Field(
|
|
920
|
+
default=None,
|
|
921
|
+
description="Exclude organizations in a specific search list."
|
|
922
|
+
)
|
|
923
|
+
|
|
924
|
+
# Sorting
|
|
925
|
+
sort_by_field: Optional[str] = Field(
|
|
926
|
+
default=None,
|
|
927
|
+
description="Sort field, e.g. 'name', 'employee_count', 'last_updated', etc."
|
|
928
|
+
)
|
|
929
|
+
|
|
930
|
+
sort_ascending: Optional[bool] = Field(
|
|
931
|
+
default=None,
|
|
932
|
+
description="Sort ascending (True) or descending (False)."
|
|
933
|
+
)
|
|
934
|
+
|
|
935
|
+
# Additional filters that might be useful
|
|
936
|
+
organization_founded_year_min: Optional[int] = Field(
|
|
937
|
+
default=None,
|
|
938
|
+
description="Minimum founding year for the organization."
|
|
939
|
+
)
|
|
940
|
+
|
|
941
|
+
organization_founded_year_max: Optional[int] = Field(
|
|
942
|
+
default=None,
|
|
943
|
+
description="Maximum founding year for the organization."
|
|
944
|
+
)
|
dhisana/utils/add_mapping.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import hashlib
|
|
2
|
-
from urllib.parse import urlparse
|
|
3
2
|
from typing import List, Optional
|
|
4
3
|
import logging
|
|
5
4
|
from typing import Optional, Dict, Any
|
|
6
|
-
from pydantic import ValidationError
|
|
7
5
|
from dhisana.schemas.sales import MessageItem
|
|
8
6
|
from dhisana.utils.cache_output_tools import (
|
|
9
7
|
retrieve_output,
|