dhisana 0.0.1.dev86__tar.gz → 0.0.1.dev231__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.
Files changed (131) hide show
  1. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/PKG-INFO +5 -2
  2. dhisana-0.0.1.dev231/README.md +257 -0
  3. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/setup.py +5 -2
  4. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/schemas/common.py +32 -0
  5. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/schemas/sales.py +221 -23
  6. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/add_mapping.py +72 -63
  7. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/apollo_tools.py +739 -109
  8. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/built_with_api_tools.py +4 -2
  9. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/cache_output_tools.py +23 -23
  10. dhisana-0.0.1.dev231/src/dhisana/utils/check_email_validity_tools.py +717 -0
  11. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/check_for_intent_signal.py +1 -2
  12. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/check_linkedin_url_validity.py +34 -8
  13. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/clay_tools.py +3 -2
  14. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/clean_properties.py +3 -1
  15. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/compose_salesnav_query.py +0 -1
  16. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/compose_search_query.py +7 -3
  17. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/composite_tools.py +0 -1
  18. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/dataframe_tools.py +2 -2
  19. dhisana-0.0.1.dev231/src/dhisana/utils/email_body_utils.py +72 -0
  20. dhisana-0.0.1.dev231/src/dhisana/utils/email_provider.py +375 -0
  21. dhisana-0.0.1.dev231/src/dhisana/utils/enrich_lead_information.py +917 -0
  22. dhisana-0.0.1.dev231/src/dhisana/utils/fetch_openai_config.py +129 -0
  23. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/field_validators.py +1 -1
  24. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/g2_tools.py +0 -1
  25. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_content.py +0 -1
  26. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_email.py +20 -10
  27. dhisana-0.0.1.dev231/src/dhisana/utils/generate_email_response.py +465 -0
  28. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_flow.py +0 -1
  29. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_linkedin_connect_message.py +19 -6
  30. dhisana-0.0.1.dev231/src/dhisana/utils/generate_linkedin_response_message.py +317 -0
  31. dhisana-0.0.1.dev231/src/dhisana/utils/generate_structured_output_internal.py +462 -0
  32. dhisana-0.0.1.dev231/src/dhisana/utils/google_custom_search.py +267 -0
  33. dhisana-0.0.1.dev231/src/dhisana/utils/google_oauth_tools.py +675 -0
  34. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/google_workspace_tools.py +340 -17
  35. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/hubspot_clearbit.py +3 -1
  36. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/hubspot_crm_tools.py +771 -167
  37. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/instantly_tools.py +3 -1
  38. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/lusha_tools.py +10 -7
  39. dhisana-0.0.1.dev231/src/dhisana/utils/mailgun_tools.py +150 -0
  40. dhisana-0.0.1.dev231/src/dhisana/utils/microsoft365_tools.py +407 -0
  41. dhisana-0.0.1.dev231/src/dhisana/utils/openai_assistant_and_file_utils.py +267 -0
  42. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/openai_helpers.py +19 -16
  43. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/parse_linkedin_messages_txt.py +2 -3
  44. dhisana-0.0.1.dev231/src/dhisana/utils/profile.py +37 -0
  45. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/proxy_curl_tools.py +430 -195
  46. dhisana-0.0.1.dev231/src/dhisana/utils/proxycurl_search_leads.py +426 -0
  47. dhisana-0.0.1.dev231/src/dhisana/utils/research_lead.py +176 -0
  48. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/sales_navigator_crawler.py +1 -6
  49. dhisana-0.0.1.dev231/src/dhisana/utils/salesforce_crm_tools.py +477 -0
  50. dhisana-0.0.1.dev231/src/dhisana/utils/search_router.py +131 -0
  51. dhisana-0.0.1.dev231/src/dhisana/utils/search_router_jobs.py +51 -0
  52. dhisana-0.0.1.dev231/src/dhisana/utils/sendgrid_tools.py +152 -0
  53. dhisana-0.0.1.dev231/src/dhisana/utils/serarch_router_local_business.py +75 -0
  54. dhisana-0.0.1.dev231/src/dhisana/utils/serpapi_additional_tools.py +290 -0
  55. dhisana-0.0.1.dev231/src/dhisana/utils/serpapi_google_jobs.py +117 -0
  56. dhisana-0.0.1.dev231/src/dhisana/utils/serpapi_google_search.py +188 -0
  57. dhisana-0.0.1.dev231/src/dhisana/utils/serpapi_local_business_search.py +129 -0
  58. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/serpapi_search_tools.py +363 -432
  59. dhisana-0.0.1.dev231/src/dhisana/utils/serperdev_google_jobs.py +125 -0
  60. dhisana-0.0.1.dev231/src/dhisana/utils/serperdev_local_business.py +154 -0
  61. dhisana-0.0.1.dev231/src/dhisana/utils/serperdev_search.py +233 -0
  62. dhisana-0.0.1.dev231/src/dhisana/utils/smtp_email_tools.py +483 -0
  63. dhisana-0.0.1.dev231/src/dhisana/utils/test_connect.py +1669 -0
  64. dhisana-0.0.1.dev231/src/dhisana/utils/trasform_json.py +173 -0
  65. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/web_download_parse_tools.py +0 -1
  66. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/zoominfo_tools.py +2 -3
  67. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/workflow/test.py +1 -1
  68. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/PKG-INFO +5 -2
  69. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/SOURCES.txt +31 -1
  70. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/requires.txt +3 -0
  71. dhisana-0.0.1.dev231/tests/test_apollo_company_search.py +216 -0
  72. dhisana-0.0.1.dev231/tests/test_apollo_lead_search.py +119 -0
  73. dhisana-0.0.1.dev231/tests/test_connectivity.py +102 -0
  74. dhisana-0.0.1.dev231/tests/test_email_body_utils.py +23 -0
  75. dhisana-0.0.1.dev231/tests/test_google_document.py +119 -0
  76. dhisana-0.0.1.dev231/tests/test_hubspot_call_logs.py +79 -0
  77. dhisana-0.0.1.dev231/tests/test_linkedin_serper.py +55 -0
  78. dhisana-0.0.1.dev231/tests/test_mcp_connectivity.py +28 -0
  79. dhisana-0.0.1.dev231/tests/test_proxycurl_get_company_search_id.py +170 -0
  80. dhisana-0.0.1.dev231/tests/test_proxycurl_job_count.py +61 -0
  81. dhisana-0.0.1.dev231/tests/test_structured_output_with_mcp.py +56 -0
  82. dhisana-0.0.1.dev86/README.md +0 -141
  83. dhisana-0.0.1.dev86/src/dhisana/utils/check_email_validity_tools.py +0 -719
  84. dhisana-0.0.1.dev86/src/dhisana/utils/enrich_lead_information.py +0 -433
  85. dhisana-0.0.1.dev86/src/dhisana/utils/generate_email_response.py +0 -208
  86. dhisana-0.0.1.dev86/src/dhisana/utils/generate_linkedin_response_message.py +0 -226
  87. dhisana-0.0.1.dev86/src/dhisana/utils/generate_structured_output_internal.py +0 -256
  88. dhisana-0.0.1.dev86/src/dhisana/utils/google_custom_search.py +0 -161
  89. dhisana-0.0.1.dev86/src/dhisana/utils/openai_assistant_and_file_utils.py +0 -323
  90. dhisana-0.0.1.dev86/src/dhisana/utils/research_lead.py +0 -123
  91. dhisana-0.0.1.dev86/src/dhisana/utils/salesforce_crm_tools.py +0 -204
  92. dhisana-0.0.1.dev86/src/dhisana/utils/sendgrid_tools.py +0 -117
  93. dhisana-0.0.1.dev86/src/dhisana/utils/test_connect.py +0 -344
  94. dhisana-0.0.1.dev86/src/dhisana/utils/trasform_json.py +0 -94
  95. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/pyproject.toml +0 -0
  96. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/setup.cfg +0 -0
  97. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/__init__.py +0 -0
  98. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/cli/__init__.py +0 -0
  99. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/cli/cli.py +0 -0
  100. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/cli/datasets.py +0 -0
  101. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/cli/models.py +0 -0
  102. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/cli/predictions.py +0 -0
  103. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/schemas/__init__.py +0 -0
  104. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/ui/__init__.py +0 -0
  105. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/ui/components.py +0 -0
  106. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/__init__.py +0 -0
  107. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/agent_tools.py +0 -0
  108. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/assistant_tool_tag.py +0 -0
  109. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/cache_output_tools_local.py +0 -0
  110. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/company_utils.py +0 -0
  111. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
  112. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/domain_parser.py +0 -0
  113. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/email_parse_helpers.py +0 -0
  114. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
  115. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
  116. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/linkedin_crawler.py +0 -0
  117. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
  118. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
  119. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
  120. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
  121. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
  122. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/python_function_to_tools.py +0 -0
  123. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/utils/workflow_code_model.py +0 -0
  124. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/workflow/__init__.py +0 -0
  125. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/workflow/agent.py +0 -0
  126. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/workflow/flow.py +0 -0
  127. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana/workflow/task.py +0 -0
  128. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/dependency_links.txt +0 -0
  129. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/entry_points.txt +0 -0
  130. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/top_level.txt +0 -0
  131. {dhisana-0.0.1.dev86 → dhisana-0.0.1.dev231}/tests/test_agent_tools.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev86
3
+ Version: 0.0.1.dev231
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
@@ -30,6 +30,9 @@ Requires-Dist: hubspot-api-client
30
30
  Requires-Dist: tldextract
31
31
  Requires-Dist: pyperclip
32
32
  Requires-Dist: azure-storage-blob
33
+ Requires-Dist: email_validator
34
+ Requires-Dist: fqdn
35
+ Requires-Dist: json_repair
33
36
  Dynamic: author
34
37
  Dynamic: author-email
35
38
  Dynamic: classifier
@@ -0,0 +1,257 @@
1
+ # Dhisana Python SDK
2
+
3
+ A Python SDK for interacting with Dhisana AI services.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install dhisana
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ from dhisana.utils.agent_tools import (
15
+ search_google_maps,
16
+ enrich_people_with_apollo,
17
+ search_google,
18
+ search_google_jobs,
19
+ search_google_news,
20
+ get_html_content_from_url,
21
+ parse_html_content,
22
+ extract_image_links,
23
+ extract_head_section_from_html_content,
24
+ get_email_if_exists,
25
+ search_crunchbase,
26
+ search_people_with_apollo,
27
+ search_companies_with_apollo,
28
+ enrich_company_with_apollo,
29
+ get_job_postings_from_apollo
30
+ )
31
+ # Your code here
32
+ ```
33
+
34
+ ## Steps to Create and Publish the Package
35
+
36
+ ### Ensure you have the latest versions of setuptools and wheel
37
+
38
+ ```bash
39
+ pip install --upgrade setuptools wheel
40
+ ```
41
+
42
+ ### Build the Package
43
+
44
+ ```bash
45
+ pip install .
46
+ ```
47
+
48
+ ### Upload to PyPI
49
+
50
+ First, install twine:
51
+
52
+ ```bash
53
+ pip install --upgrade build twine
54
+ python -m build
55
+ pip install twine
56
+ ```
57
+
58
+ ### Then upload your package (you'll need a PyPI account)
59
+
60
+ ```bash
61
+ twine upload dist/\*
62
+ ```
63
+
64
+ ### Install the Package Locally for Testing
65
+
66
+ You can install the package locally to test it before uploading:
67
+
68
+ ```bash
69
+ pip install -e .
70
+ ```
71
+
72
+ The -e flag installs the package in editable mode, which is useful during development.
73
+
74
+ ## Run Tests
75
+
76
+ ```bash
77
+ pip install pytest
78
+ pytest tests/
79
+ ```
80
+
81
+ ### Using the Package in Other Projects
82
+
83
+ Once your package is published to PyPI, other users can install it using:
84
+
85
+ ```bash
86
+ pip install dhisana
87
+ ```
88
+
89
+ They can then import your SDK as:
90
+
91
+ ```bash
92
+ from dhisana.utils.agent_tools import (
93
+ search_google_maps,
94
+ enrich_people_with_apollo,
95
+ search_google,
96
+ search_google_jobs,
97
+ search_google_news,
98
+ get_html_content_from_url,
99
+ parse_html_content,
100
+ extract_image_links,
101
+ extract_head_section_from_html_content,
102
+ get_email_if_exists,
103
+ search_crunchbase,
104
+ search_people_with_apollo,
105
+ search_companies_with_apollo,
106
+ enrich_company_with_apollo,
107
+ get_job_postings_from_apollo
108
+ )
109
+
110
+ # Use the functionalities provided by your SDK
111
+ ```
112
+
113
+ ### To use locally
114
+
115
+ ```bash
116
+ pip install -e /path/to/other/project
117
+ ```
118
+
119
+ ### To use CLI
120
+
121
+ You can use the CLI provided by the Dhisana AI SDK. To see the available commands and options, use:
122
+
123
+ ```bash
124
+ dhisana --help
125
+ ```
126
+
127
+ This will display:
128
+
129
+ ```bash
130
+ Usage: dhisana [OPTIONS] COMMAND [ARGS]...
131
+
132
+ Dhisana AI SDK CLI.
133
+
134
+ Options:
135
+ --help Show this message and exit.
136
+
137
+ Commands:
138
+ dataset-cli Commands for managing datasets.
139
+ model-cli Commands for managing models.
140
+ prediction-cli Commands for running predictions.
141
+ ```
142
+
143
+ ## Proxycurl Job Leads Example
144
+
145
+ Set `PROXY_CURL_API_KEY` in your environment before running functions that call Proxycurl.
146
+
147
+ ```bash
148
+ export PROXY_CURL_API_KEY=your_api_key
149
+ ```
150
+
151
+ Example usage to search for SDR roles and retrieve hiring manager leads:
152
+
153
+ ```python
154
+ import asyncio
155
+ from dhisana.utils.proxy_curl_tools import find_leads_by_job_openings_proxy_curl
156
+
157
+ async def main():
158
+ leads = await find_leads_by_job_openings_proxy_curl(
159
+ {"job_title": "SDR", "location": "United States"},
160
+ hiring_manager_roles=["VP of Sales", "Head of Sales"],
161
+ )
162
+ print(leads)
163
+
164
+ asyncio.run(main())
165
+ ```
166
+
167
+ ## Proxycurl Job Search Example
168
+
169
+ Use `proxycurl_job_search` to list jobs posted by a company. Parameters mirror
170
+ Proxycurl's job search endpoint.
171
+
172
+ ### Parameters
173
+
174
+ - `job_type` – one of `full-time`, `part-time`, `contract`, `internship`,
175
+ `temporary`, `volunteer`, or `anything`.
176
+ - `experience_level` – `internship`, `entry_level`, `associate`,
177
+ `mid_senior_level`, `director`, or `anything`.
178
+ - `when` – posted time such as `yesterday`, `past-week`, `past-month`, or
179
+ `anytime`.
180
+ - `flexibility` – `remote`, `on-site`, `hybrid`, or `anything`.
181
+ - `geo_id` – location identifier, e.g. `92000000` for worldwide.
182
+ - `keyword` – keyword to match in the job title.
183
+ - `search_id` – company search identifier from the Company Profile API.
184
+
185
+ Example usage:
186
+
187
+ ```python
188
+ import asyncio
189
+ from dhisana.utils.proxycurl_search_leads import JobSearchParams, proxycurl_job_search
190
+
191
+ async def main():
192
+ jobs = await proxycurl_job_search(
193
+ JobSearchParams(
194
+ search_id="2790400",
195
+ keyword="engineer",
196
+ job_type="full-time",
197
+ experience_level="mid_senior_level",
198
+ when="past-month",
199
+ flexibility="remote",
200
+ geo_id=92000000,
201
+ ),
202
+ max_entries=2,
203
+ )
204
+ print(jobs)
205
+
206
+ asyncio.run(main())
207
+ ```
208
+
209
+ ## Proxycurl Get Company Search ID Example
210
+
211
+ Use `proxycurl_get_company_search_id` to retrieve a company's search ID, which is required for other Proxycurl operations like job searches. This function calls Proxycurl's Company Profile endpoint.
212
+
213
+ ### Function Parameters
214
+
215
+ - `company_url` – LinkedIn company profile URL (e.g., `https://www.linkedin.com/company/microsoft/`)
216
+ - `tool_config` – Optional tool configuration containing API key
217
+
218
+ ### Return Value
219
+
220
+ Returns a dictionary with:
221
+
222
+ - `search_id` – The company's search ID (required for job operations)
223
+ - `name` – Company name
224
+ - `linkedin_internal_id` – LinkedIn's internal company ID
225
+ - `industry` – Company industry
226
+ - `company_url` – The original URL provided
227
+ - `error` – Error message (if any errors occurred)
228
+
229
+ Example usage:
230
+
231
+ ```python
232
+ import asyncio
233
+ from dhisana.utils.proxycurl_search_leads import (
234
+ proxycurl_get_company_search_id,
235
+ proxycurl_job_count,
236
+ JobSearchParams
237
+ )
238
+
239
+ async def main():
240
+ # Get company search ID
241
+ company_result = await proxycurl_get_company_search_id(
242
+ "https://www.linkedin.com/company/microsoft/"
243
+ )
244
+
245
+ if company_result.get("search_id"):
246
+ print(f"Company: {company_result['name']}")
247
+ print(f"Search ID: {company_result['search_id']}")
248
+
249
+ # Use the search ID for job operations
250
+ job_params = JobSearchParams(search_id=company_result["search_id"])
251
+ job_count = await proxycurl_job_count(job_params)
252
+ print(f"Total jobs: {job_count.get('count', 0)}")
253
+ else:
254
+ print(f"Error: {company_result.get('error')}")
255
+
256
+ asyncio.run(main())
257
+ ```
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='dhisana',
5
- version='0.0.1-dev86',
5
+ version='0.0.1-dev231',
6
6
  description='A Python SDK for Dhisana AI Platform',
7
7
  author='Admin',
8
8
  author_email='contact@dhisana.ai',
@@ -29,7 +29,10 @@ setup(
29
29
  'hubspot-api-client',
30
30
  'tldextract',
31
31
  'pyperclip',
32
- 'azure-storage-blob'
32
+ 'azure-storage-blob',
33
+ 'email_validator',
34
+ 'fqdn',
35
+ 'json_repair'
33
36
  ],
34
37
  entry_points={
35
38
  'console_scripts': [
@@ -363,3 +363,35 @@ class Integration(IntegrationBase):
363
363
 
364
364
  Integration.model_rebuild()
365
365
  IntegrationUpdate.model_rebuild()
366
+
367
+ class BodyFormat(str, Enum):
368
+ AUTO = "auto"
369
+ HTML = "html"
370
+ TEXT = "text"
371
+
372
+
373
+ class SendEmailContext(BaseModel):
374
+ recipient: str
375
+ subject: str
376
+ body: str
377
+ sender_name: str
378
+ sender_email: str
379
+ labels: Optional[List[str]]
380
+ body_format: BodyFormat = BodyFormat.AUTO
381
+
382
+ class QueryEmailContext(BaseModel):
383
+ start_time: str
384
+ end_time: str
385
+ sender_email: str
386
+ unread_only: bool = True
387
+ labels: Optional[List[str]] = None
388
+
389
+
390
+ class ReplyEmailContext(BaseModel):
391
+ message_id: str
392
+ reply_body: str
393
+ sender_email: str
394
+ sender_name: str
395
+ mark_as_read: str = "True"
396
+ add_labels: Optional[List[str]] = None
397
+ reply_body_format: BodyFormat = BodyFormat.AUTO
@@ -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[str] = None
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
- assigned_to: Optional[str] = None
31
- engaged: Optional[bool] = None
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
- Literal["not_started", "in_progress", "valid", "invalid"]
38
- ] = None
39
- linkedin_validation_status: Optional[
40
- Literal["not_started", "in_progress", "valid", "invalid"]
41
- ] = None
42
- research_status: Optional[
43
- Literal["not_started", "in_progress", "done", "failed"]
44
- ] = None
45
- enchrichment_status: Optional[
46
- Literal["not_started", "in_progress", "done", "failed"]
47
- ] = None
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):
@@ -243,6 +294,7 @@ class MessageGenerationInstructions(BaseModel):
243
294
  """
244
295
  instructions_to_generate_message: Optional[str] = None
245
296
  prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
297
+ use_cache: Optional[bool] = True
246
298
 
247
299
  class CampaignContext(BaseModel):
248
300
  """
@@ -272,6 +324,10 @@ class MessageItem(BaseModel):
272
324
  ...,
273
325
  description="Unique identifier for the message"
274
326
  )
327
+ thread_id: str = Field(
328
+ ...,
329
+ description="Unique identifier for the conversation thread"
330
+ )
275
331
  sender_name: str = Field(
276
332
  ...,
277
333
  description="Sender's display name (if available)"
@@ -300,6 +356,7 @@ class MessageItem(BaseModel):
300
356
  ...,
301
357
  description="Body of the message in plain text"
302
358
  )
359
+ html_body: Optional[str] = None
303
360
 
304
361
  class MessageResponse(BaseModel):
305
362
  """
@@ -435,14 +492,14 @@ class HubSpotLeadInformation(BaseModel):
435
492
  organization_name: str = Field("", description="Current Company where lead works")
436
493
  organization_website: str = Field("", description="Current Company website of the lead")
437
494
  organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
438
- additional_properties: Optional[Dict[str, str]] = None
495
+ additional_properties: Optional[Dict[str, Any]] = None
439
496
 
440
497
  class HubSpotCompanyinformation(BaseModel):
441
498
  primary_domain_of_organization: str = Field("", description="Primary domain of the organization")
442
499
  organization_name: str = Field("", description="Current Company where lead works")
443
500
  organization_website: str = Field("", description="Current Company website of the lead")
444
501
  organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
445
- additional_properties: Optional[Dict[str, str]] = None
502
+ additional_properties: Optional[Dict[str, Any]] = None
446
503
 
447
504
 
448
505
  # --------------------------------------------------------------------
@@ -459,6 +516,7 @@ HUBSPOT_TO_LEAD_MAPPING = {
459
516
  "address": "lead_location", # You can choose "city", "state", etc. if you prefer
460
517
  "city": "lead_location",
461
518
  "domain": "primary_domain_of_organization",
519
+ "hs_linkedin_url": "user_linkedin_url",
462
520
  }
463
521
 
464
522
  class SmartListStatus(str, Enum):
@@ -478,6 +536,12 @@ class SmartListSourceType(str, Enum):
478
536
  CSV = "CSV"
479
537
  GOOGLE_SHEETS = "GOOGLE_SHEETS"
480
538
  CUSTOM_WEBSITE = "CUSTOM_WEBSITE"
539
+ GITHUB = "GITHUB"
540
+ ICP_SEARCH = "ICP_SEARCH"
541
+ LOCAL_BUSINESS = "LOCAL_BUSINESS"
542
+ GOOGLE_JOBS = "GOOGLE_JOBS"
543
+ WEBHOOK = "WEBHOOK"
544
+ GOOGLE_CUSTOM_SITE_SEARCH = "GOOGLE_CUSTOM_SITE_SEARCH"
481
545
 
482
546
  class SourceConfiguration(BaseModel):
483
547
  """
@@ -494,6 +558,15 @@ class SourceConfiguration(BaseModel):
494
558
  file_path: Optional[str] = None
495
559
  # For Google Sheets
496
560
  source_url: Optional[str] = None
561
+ # For Github
562
+ github_search_query: Optional[str] = None
563
+ github_max_repos: Optional[int] = None
564
+ github_max_contributors: Optional[int] = None
565
+
566
+ # Custom website inputs
567
+ custom_instructions_for_doing_pagination: Optional[str] = None
568
+ custom_instructions_for_data_extraction_from_page: Optional[str] = None
569
+ custom_instruction_to_fetch_details_page: Optional[str] = None
497
570
 
498
571
  class SmartListSource(BaseModel):
499
572
  """
@@ -555,6 +628,8 @@ class SmartListLead(BaseModel):
555
628
  organization_linkedin_url: Optional[str] = None
556
629
  organization_linkedin_salesnav_url: Optional[str] = None
557
630
  primary_domain_of_organization: Optional[str] = None
631
+ twitter_handle: Optional[str] = None
632
+ github_handle: Optional[str] = None
558
633
  job_title: Optional[str] = None
559
634
  phone: Optional[str] = None
560
635
  headline: Optional[str] = None
@@ -562,13 +637,18 @@ class SmartListLead(BaseModel):
562
637
  organization_name: Optional[str] = None
563
638
  organization_website: Optional[str] = None
564
639
  summary_about_lead: Optional[str] = None
565
- keywords: Optional[List[str]] = None
566
- additional_properties: Optional[Dict[str, str]] = None
640
+ keywords: Optional[Any] = None
641
+ additional_properties: Optional[Dict[str, Any]] = None
567
642
  research_summary: Optional[str] = None
568
643
 
569
644
  qualification_score: Optional[float] = None
570
645
  qualification_reason: Optional[str] = None
571
646
  source: Optional[str] = None
647
+
648
+ email_validation_status: Optional[str] = None
649
+ linkedin_validation_status: Optional[str] = None
650
+ research_status: Optional[str] = None
651
+ enchrichment_status: Optional[str] = None
572
652
 
573
653
  agent_instance_id: Optional[UUID] = None
574
654
  organization_id: Optional[UUID] = None
@@ -576,7 +656,10 @@ class SmartListLead(BaseModel):
576
656
  created_at: Optional[int] = None
577
657
  updated_by: Optional[UUID] = None
578
658
  updated_at: Optional[int] = None
579
-
659
+
660
+ revenue: Optional[str] = None
661
+ company_size: Optional[str] = None
662
+ industry: Optional[str] = None
580
663
  class Config:
581
664
  from_attributes = True
582
665
 
@@ -741,3 +824,118 @@ class LeadsQueryFilters(BaseModel):
741
824
  description="Ranges for organization number of employees."
742
825
  )
743
826
 
827
+
828
+ class CompanyQueryFilters(BaseModel):
829
+ """
830
+ Defines the filter parameters for querying companies/organizations in the Apollo database.
831
+ All fields are optional and default to None if not specified by user.
832
+ """
833
+
834
+ # Core company search parameters
835
+ organization_locations: Optional[List[str]] = Field(
836
+ default=None,
837
+ description="List of organization headquarters locations (city, state, country)."
838
+ )
839
+
840
+ organization_num_employees_ranges: Optional[List[str]] = Field(
841
+ default=None,
842
+ description="Employee count ranges, e.g. ['1,10', '11,50', '51,200']. Use specific ranges."
843
+ )
844
+
845
+ min_employees: Optional[int] = Field(
846
+ default=None,
847
+ description="Minimum number of employees (>=1). Internally converted to a numeric range."
848
+ )
849
+
850
+ max_employees: Optional[int] = Field(
851
+ default=None,
852
+ description="Maximum number of employees (<=100000). Internally converted to a numeric range."
853
+ )
854
+
855
+ organization_industries: Optional[List[str]] = Field(
856
+ default=None,
857
+ description="List of organization industries."
858
+ )
859
+
860
+ organization_industry_tag_ids: Optional[List[str]] = Field(
861
+ default=None,
862
+ description="List of industry tag IDs, e.g. ['5567cd4773696439b10b0000']."
863
+ )
864
+
865
+ # Revenue filters
866
+ revenue_range_min: Optional[int] = Field(
867
+ default=None,
868
+ description="Minimum company revenue in USD."
869
+ )
870
+
871
+ revenue_range_max: Optional[int] = Field(
872
+ default=None,
873
+ description="Maximum company revenue in USD."
874
+ )
875
+
876
+ # Funding and growth
877
+ organization_latest_funding_stage_cd: Optional[List[str]] = Field(
878
+ default=None,
879
+ description="List of funding stage codes, e.g. ['2', '3', '10']."
880
+ )
881
+
882
+ # Technology and keywords
883
+ currently_using_any_of_technology_uids: Optional[List[str]] = Field(
884
+ default=None,
885
+ description="Technology UIDs used by the organization, e.g. ['google_font_api']."
886
+ )
887
+
888
+ q_keywords: Optional[str] = Field(
889
+ default=None,
890
+ description="Keywords to search for in company descriptions, names, etc."
891
+ )
892
+
893
+ q_organization_domains: Optional[List[str]] = Field(
894
+ default=None,
895
+ description="Specific company domains to search for, e.g. ['microsoft.com', 'google.com']."
896
+ )
897
+
898
+ # Company-specific filters
899
+ organization_ids: Optional[List[str]] = Field(
900
+ default=None,
901
+ description="Specific Apollo organization IDs to include."
902
+ )
903
+
904
+ not_organization_ids: Optional[List[str]] = Field(
905
+ default=None,
906
+ description="Apollo organization IDs to exclude from results."
907
+ )
908
+
909
+ # Search lists
910
+ q_organization_search_list_id: Optional[str] = Field(
911
+ default=None,
912
+ description="Include only organizations in a specific search list."
913
+ )
914
+
915
+ q_not_organization_search_list_id: Optional[str] = Field(
916
+ default=None,
917
+ description="Exclude organizations in a specific search list."
918
+ )
919
+
920
+ # Sorting
921
+ sort_by_field: Optional[str] = Field(
922
+ default=None,
923
+ description="Sort field, e.g. 'name', 'employee_count', 'last_updated', etc."
924
+ )
925
+
926
+ sort_ascending: Optional[bool] = Field(
927
+ default=None,
928
+ description="Sort ascending (True) or descending (False)."
929
+ )
930
+
931
+ # Additional filters that might be useful
932
+ organization_founded_year_min: Optional[int] = Field(
933
+ default=None,
934
+ description="Minimum founding year for the organization."
935
+ )
936
+
937
+ organization_founded_year_max: Optional[int] = Field(
938
+ default=None,
939
+ description="Maximum founding year for the organization."
940
+ )
941
+