dhisana 0.0.1.dev121__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.
Files changed (130) hide show
  1. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/PKG-INFO +1 -1
  2. dhisana-0.0.1.dev257/README.md +257 -0
  3. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/setup.py +1 -1
  4. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/schemas/common.py +13 -1
  5. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/schemas/sales.py +233 -24
  6. dhisana-0.0.1.dev257/src/dhisana/utils/apollo_tools.py +1728 -0
  7. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/built_with_api_tools.py +4 -2
  8. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/cache_output_tools.py +22 -2
  9. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_email_validity_tools.py +39 -21
  10. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_linkedin_url_validity.py +34 -6
  11. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/clay_tools.py +3 -1
  12. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_search_query.py +7 -2
  13. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/dataframe_tools.py +2 -2
  14. dhisana-0.0.1.dev257/src/dhisana/utils/email_body_utils.py +72 -0
  15. dhisana-0.0.1.dev257/src/dhisana/utils/email_provider.py +375 -0
  16. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/enrich_lead_information.py +180 -48
  17. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/fetch_openai_config.py +9 -3
  18. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_content.py +3 -1
  19. dhisana-0.0.1.dev257/src/dhisana/utils/generate_custom_message.py +271 -0
  20. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_email.py +66 -15
  21. dhisana-0.0.1.dev257/src/dhisana/utils/generate_email_response.py +480 -0
  22. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_linkedin_connect_message.py +9 -2
  23. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_linkedin_response_message.py +137 -73
  24. dhisana-0.0.1.dev257/src/dhisana/utils/generate_structured_output_internal.py +462 -0
  25. dhisana-0.0.1.dev257/src/dhisana/utils/google_custom_search.py +267 -0
  26. dhisana-0.0.1.dev257/src/dhisana/utils/google_oauth_tools.py +727 -0
  27. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/google_workspace_tools.py +312 -57
  28. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/hubspot_clearbit.py +3 -1
  29. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/hubspot_crm_tools.py +718 -272
  30. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/instantly_tools.py +3 -1
  31. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/lusha_tools.py +8 -3
  32. dhisana-0.0.1.dev257/src/dhisana/utils/mailgun_tools.py +156 -0
  33. dhisana-0.0.1.dev257/src/dhisana/utils/mailreach_tools.py +123 -0
  34. dhisana-0.0.1.dev257/src/dhisana/utils/microsoft365_tools.py +455 -0
  35. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openai_assistant_and_file_utils.py +3 -3
  36. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openai_helpers.py +6 -4
  37. dhisana-0.0.1.dev257/src/dhisana/utils/profile.py +37 -0
  38. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/proxy_curl_tools.py +382 -77
  39. dhisana-0.0.1.dev257/src/dhisana/utils/proxycurl_search_leads.py +426 -0
  40. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/research_lead.py +3 -3
  41. dhisana-0.0.1.dev257/src/dhisana/utils/salesforce_crm_tools.py +477 -0
  42. dhisana-0.0.1.dev257/src/dhisana/utils/search_router.py +131 -0
  43. dhisana-0.0.1.dev257/src/dhisana/utils/search_router_jobs.py +51 -0
  44. dhisana-0.0.1.dev257/src/dhisana/utils/sendgrid_tools.py +162 -0
  45. dhisana-0.0.1.dev257/src/dhisana/utils/serarch_router_local_business.py +75 -0
  46. dhisana-0.0.1.dev257/src/dhisana/utils/serpapi_additional_tools.py +290 -0
  47. dhisana-0.0.1.dev257/src/dhisana/utils/serpapi_google_jobs.py +117 -0
  48. dhisana-0.0.1.dev257/src/dhisana/utils/serpapi_google_search.py +188 -0
  49. dhisana-0.0.1.dev257/src/dhisana/utils/serpapi_local_business_search.py +129 -0
  50. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/serpapi_search_tools.py +353 -424
  51. dhisana-0.0.1.dev257/src/dhisana/utils/serperdev_google_jobs.py +125 -0
  52. dhisana-0.0.1.dev257/src/dhisana/utils/serperdev_local_business.py +154 -0
  53. dhisana-0.0.1.dev257/src/dhisana/utils/serperdev_search.py +233 -0
  54. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/smtp_email_tools.py +183 -15
  55. dhisana-0.0.1.dev257/src/dhisana/utils/test_connect.py +2212 -0
  56. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/trasform_json.py +2 -1
  57. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/zoominfo_tools.py +2 -2
  58. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/test.py +1 -1
  59. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/PKG-INFO +1 -1
  60. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/SOURCES.txt +31 -1
  61. dhisana-0.0.1.dev257/tests/test_apollo_company_search.py +260 -0
  62. dhisana-0.0.1.dev257/tests/test_apollo_lead_search.py +127 -0
  63. dhisana-0.0.1.dev257/tests/test_connectivity.py +118 -0
  64. dhisana-0.0.1.dev257/tests/test_email_body_utils.py +23 -0
  65. dhisana-0.0.1.dev257/tests/test_google_document.py +119 -0
  66. dhisana-0.0.1.dev257/tests/test_hubspot_call_logs.py +79 -0
  67. dhisana-0.0.1.dev257/tests/test_linkedin_serper.py +55 -0
  68. dhisana-0.0.1.dev257/tests/test_mailreach.py +179 -0
  69. dhisana-0.0.1.dev257/tests/test_mcp_connectivity.py +28 -0
  70. dhisana-0.0.1.dev257/tests/test_proxycurl_get_company_search_id.py +170 -0
  71. dhisana-0.0.1.dev257/tests/test_proxycurl_job_count.py +61 -0
  72. dhisana-0.0.1.dev257/tests/test_structured_output_with_mcp.py +56 -0
  73. dhisana-0.0.1.dev121/README.md +0 -141
  74. dhisana-0.0.1.dev121/src/dhisana/utils/apollo_tools.py +0 -962
  75. dhisana-0.0.1.dev121/src/dhisana/utils/email_provider.py +0 -235
  76. dhisana-0.0.1.dev121/src/dhisana/utils/generate_email_response.py +0 -305
  77. dhisana-0.0.1.dev121/src/dhisana/utils/generate_structured_output_internal.py +0 -255
  78. dhisana-0.0.1.dev121/src/dhisana/utils/google_custom_search.py +0 -161
  79. dhisana-0.0.1.dev121/src/dhisana/utils/salesforce_crm_tools.py +0 -204
  80. dhisana-0.0.1.dev121/src/dhisana/utils/sendgrid_tools.py +0 -117
  81. dhisana-0.0.1.dev121/src/dhisana/utils/test_connect.py +0 -543
  82. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/pyproject.toml +0 -0
  83. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/setup.cfg +0 -0
  84. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/__init__.py +0 -0
  85. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/__init__.py +0 -0
  86. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/cli.py +0 -0
  87. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/datasets.py +0 -0
  88. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/models.py +0 -0
  89. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/predictions.py +0 -0
  90. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/schemas/__init__.py +0 -0
  91. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/ui/__init__.py +0 -0
  92. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/ui/components.py +0 -0
  93. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/__init__.py +0 -0
  94. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/add_mapping.py +0 -0
  95. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/agent_tools.py +0 -0
  96. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/assistant_tool_tag.py +0 -0
  97. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/cache_output_tools_local.py +0 -0
  98. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_for_intent_signal.py +0 -0
  99. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/clean_properties.py +0 -0
  100. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/company_utils.py +0 -0
  101. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_salesnav_query.py +0 -0
  102. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
  103. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/composite_tools.py +0 -0
  104. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/domain_parser.py +0 -0
  105. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/email_parse_helpers.py +0 -0
  106. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
  107. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/field_validators.py +0 -0
  108. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/g2_tools.py +0 -0
  109. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_flow.py +0 -0
  110. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
  111. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/linkedin_crawler.py +0 -0
  112. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
  113. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
  114. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
  115. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
  116. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
  117. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
  118. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/python_function_to_tools.py +0 -0
  119. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
  120. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/web_download_parse_tools.py +0 -0
  121. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/workflow_code_model.py +0 -0
  122. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/__init__.py +0 -0
  123. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/agent.py +0 -0
  124. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/flow.py +0 -0
  125. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/task.py +0 -0
  126. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/dependency_links.txt +0 -0
  127. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/entry_points.txt +0 -0
  128. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/requires.txt +0 -0
  129. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/top_level.txt +0 -0
  130. {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/tests/test_agent_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev121
3
+ Version: 0.0.1.dev257
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
@@ -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-dev121',
5
+ version='0.0.1-dev257',
6
6
  description='A Python SDK for Dhisana AI Platform',
7
7
  author='Admin',
8
8
  author_email='contact@dhisana.ai',
@@ -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,9 @@ 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
381
+ headers: Optional[Dict[str, str]] = None
382
+ email_open_token: Optional[str] = None
374
383
 
375
384
  class QueryEmailContext(BaseModel):
376
385
  start_time: str
@@ -385,5 +394,8 @@ class ReplyEmailContext(BaseModel):
385
394
  reply_body: str
386
395
  sender_email: str
387
396
  sender_name: str
397
+ headers: Optional[Dict[str, str]] = None
398
+ fallback_recipient: Optional[str] = None
388
399
  mark_as_read: str = "True"
389
- add_labels: Optional[List[str]] = None
400
+ add_labels: Optional[List[str]] = None
401
+ reply_body_format: BodyFormat = BodyFormat.AUTO
@@ -1,5 +1,7 @@
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
@@ -10,14 +12,20 @@ from typing import Optional, List, Dict, Literal
10
12
  # -----------------------------
11
13
 
12
14
  class Lead(BaseModel):
13
- id: Optional[str] = None
15
+ id: Optional[UUID] = None
14
16
  full_name: Optional[str] = None
15
17
  first_name: Optional[str] = None
16
18
  last_name: Optional[str] = None
17
19
  email: Optional[str] = None
18
20
  user_linkedin_url: Optional[str] = None
19
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
20
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
21
29
  job_title: Optional[str] = None
22
30
  phone: Optional[str] = None
23
31
  headline: Optional[str] = None
@@ -25,25 +33,69 @@ class Lead(BaseModel):
25
33
  organization_name: Optional[str] = None
26
34
  organization_website: Optional[str] = None
27
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]] = {}
28
47
  workflow_stage: Optional[str] = None
29
- assigned_to: Optional[str] = None
30
- engaged: Optional[bool] = None
48
+
49
+ engaged: bool = False
31
50
  last_contact: Optional[int] = None
32
- additional_properties: Optional[Dict[str, str]] = None
33
51
  research_summary: Optional[str] = None
34
52
  task_ids: Optional[List[str]] = None
35
- email_validation_status: Optional[
36
- Literal["not_started", "in_progress", "valid", "invalid"]
37
- ] = None
38
- linkedin_validation_status: Optional[
39
- Literal["not_started", "in_progress", "valid", "invalid"]
40
- ] = None
41
- research_status: Optional[
42
- Literal["not_started", "in_progress", "done", "failed"]
43
- ] = None
44
- enchrichment_status: Optional[
45
- Literal["not_started", "in_progress", "done", "failed"]
46
- ] = 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)]
47
99
 
48
100
 
49
101
  class LeadList(BaseModel):
@@ -218,6 +270,7 @@ class ChannelType(str, Enum):
218
270
  LINKEDIN_CONNECT_MESSAGE = "linkedin_connect_message"
219
271
  REPLY_EMAIL = "reply_email"
220
272
  LINKEDIN_USER_MESSAGE = "linkedin_user_message"
273
+ CUSTOM_MESSAGE = "custom_message"
221
274
 
222
275
  class SenderInfo(BaseModel):
223
276
  """
@@ -239,9 +292,14 @@ class MessageGenerationInstructions(BaseModel):
239
292
  Holds the user-supplied instructions for generating the message:
240
293
  - instructions_to_generate_message: Plain text or template instructions from the user.
241
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.
242
297
  """
243
298
  instructions_to_generate_message: Optional[str] = None
244
299
  prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
300
+ use_cache: Optional[bool] = True
301
+ allow_html: Optional[bool] = False
302
+ html_template: Optional[str] = None
245
303
 
246
304
  class CampaignContext(BaseModel):
247
305
  """
@@ -303,6 +361,7 @@ class MessageItem(BaseModel):
303
361
  ...,
304
362
  description="Body of the message in plain text"
305
363
  )
364
+ html_body: Optional[str] = None
306
365
 
307
366
  class MessageResponse(BaseModel):
308
367
  """
@@ -438,14 +497,14 @@ class HubSpotLeadInformation(BaseModel):
438
497
  organization_name: str = Field("", description="Current Company where lead works")
439
498
  organization_website: str = Field("", description="Current Company website of the lead")
440
499
  organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
441
- additional_properties: Optional[Dict[str, str]] = None
500
+ additional_properties: Optional[Dict[str, Any]] = None
442
501
 
443
502
  class HubSpotCompanyinformation(BaseModel):
444
503
  primary_domain_of_organization: str = Field("", description="Primary domain of the organization")
445
504
  organization_name: str = Field("", description="Current Company where lead works")
446
505
  organization_website: str = Field("", description="Current Company website of the lead")
447
506
  organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
448
- additional_properties: Optional[Dict[str, str]] = None
507
+ additional_properties: Optional[Dict[str, Any]] = None
449
508
 
450
509
 
451
510
  # --------------------------------------------------------------------
@@ -462,6 +521,7 @@ HUBSPOT_TO_LEAD_MAPPING = {
462
521
  "address": "lead_location", # You can choose "city", "state", etc. if you prefer
463
522
  "city": "lead_location",
464
523
  "domain": "primary_domain_of_organization",
524
+ "hs_linkedin_url": "user_linkedin_url",
465
525
  }
466
526
 
467
527
  class SmartListStatus(str, Enum):
@@ -482,6 +542,11 @@ class SmartListSourceType(str, Enum):
482
542
  GOOGLE_SHEETS = "GOOGLE_SHEETS"
483
543
  CUSTOM_WEBSITE = "CUSTOM_WEBSITE"
484
544
  GITHUB = "GITHUB"
545
+ ICP_SEARCH = "ICP_SEARCH"
546
+ LOCAL_BUSINESS = "LOCAL_BUSINESS"
547
+ GOOGLE_JOBS = "GOOGLE_JOBS"
548
+ WEBHOOK = "WEBHOOK"
549
+ GOOGLE_CUSTOM_SITE_SEARCH = "GOOGLE_CUSTOM_SITE_SEARCH"
485
550
 
486
551
  class SourceConfiguration(BaseModel):
487
552
  """
@@ -577,13 +642,18 @@ class SmartListLead(BaseModel):
577
642
  organization_name: Optional[str] = None
578
643
  organization_website: Optional[str] = None
579
644
  summary_about_lead: Optional[str] = None
580
- keywords: Optional[List[str]] = None
645
+ keywords: Optional[Any] = None
581
646
  additional_properties: Optional[Dict[str, Any]] = None
582
647
  research_summary: Optional[str] = None
583
648
 
584
649
  qualification_score: Optional[float] = None
585
650
  qualification_reason: Optional[str] = None
586
651
  source: Optional[str] = None
652
+
653
+ email_validation_status: Optional[str] = None
654
+ linkedin_validation_status: Optional[str] = None
655
+ research_status: Optional[str] = None
656
+ enchrichment_status: Optional[str] = None
587
657
 
588
658
  agent_instance_id: Optional[UUID] = None
589
659
  organization_id: Optional[UUID] = None
@@ -595,7 +665,6 @@ class SmartListLead(BaseModel):
595
665
  revenue: Optional[str] = None
596
666
  company_size: Optional[str] = None
597
667
  industry: Optional[str] = None
598
-
599
668
  class Config:
600
669
  from_attributes = True
601
670
 
@@ -659,7 +728,10 @@ class LeadsQueryFilters(BaseModel):
659
728
  # CHANGED: Renamed to be more descriptive
660
729
  industries: Optional[List[str]] = Field(
661
730
  default=None,
662
- description="List of organization industries. Maps to organization_industries in Apollo."
731
+ description=(
732
+ "List of organization industries (case sensitive). "
733
+ "Maps to organization_industries in Apollo."
734
+ )
663
735
  )
664
736
 
665
737
  # Potential existing fields
@@ -685,7 +757,7 @@ class LeadsQueryFilters(BaseModel):
685
757
  # CHANGED: Renamed to be more descriptive
686
758
  company_domains: Optional[List[str]] = Field(
687
759
  default=None,
688
- description="Domains of the person's employer (e.g., ['microsoft.com']). Maps to q_organization_domains."
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."
689
761
  )
690
762
 
691
763
  # CHANGED: Renamed to be more descriptive
@@ -731,7 +803,20 @@ class LeadsQueryFilters(BaseModel):
731
803
  # CHANGED: Renamed for consistency
732
804
  company_industry_tag_ids: Optional[List[str]] = Field(
733
805
  default=None,
734
- description="List of industry tag IDs, e.g. ['5567cd4773696439b10b0000']. Maps to organization_industry_tag_ids."
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"
735
820
  )
736
821
 
737
822
  q_organization_search_list_id: Optional[str] = Field(
@@ -760,3 +845,127 @@ class LeadsQueryFilters(BaseModel):
760
845
  description="Ranges for organization number of employees."
761
846
  )
762
847
 
848
+
849
+ class CompanyQueryFilters(BaseModel):
850
+ """
851
+ Defines the filter parameters for querying companies/organizations in the Apollo database.
852
+ All fields are optional and default to None if not specified by user.
853
+ """
854
+
855
+ # Core company search parameters
856
+ organization_locations: Optional[List[str]] = Field(
857
+ default=None,
858
+ description="List of organization headquarters locations (city, state, country)."
859
+ )
860
+
861
+ organization_num_employees_ranges: Optional[List[str]] = Field(
862
+ default=None,
863
+ description="Employee count ranges, e.g. ['1,10', '11,50', '51,200']. Use specific ranges."
864
+ )
865
+
866
+ min_employees: Optional[int] = Field(
867
+ default=None,
868
+ description="Minimum number of employees (>=1). Internally converted to a numeric range."
869
+ )
870
+
871
+ max_employees: Optional[int] = Field(
872
+ default=None,
873
+ description="Maximum number of employees (<=100000). Internally converted to a numeric range."
874
+ )
875
+
876
+ organization_industries: Optional[List[str]] = Field(
877
+ default=None,
878
+ description="List of organization industries."
879
+ )
880
+
881
+ organization_industry_tag_ids: Optional[List[str]] = Field(
882
+ default=None,
883
+ description="List of industry tag IDs, e.g. ['5567cd4773696439b10b0000']."
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
+ )
895
+
896
+ # Revenue filters
897
+ revenue_range_min: Optional[int] = Field(
898
+ default=None,
899
+ description="Minimum company revenue in USD."
900
+ )
901
+
902
+ revenue_range_max: Optional[int] = Field(
903
+ default=None,
904
+ description="Maximum company revenue in USD."
905
+ )
906
+
907
+ # Funding and growth
908
+ organization_latest_funding_stage_cd: Optional[List[str]] = Field(
909
+ default=None,
910
+ description="List of funding stage codes, e.g. ['2', '3', '10']."
911
+ )
912
+
913
+ # Technology and keywords
914
+ currently_using_any_of_technology_uids: Optional[List[str]] = Field(
915
+ default=None,
916
+ description="Technology UIDs used by the organization, e.g. ['google_font_api']."
917
+ )
918
+
919
+ q_keywords: Optional[str] = Field(
920
+ default=None,
921
+ description="Keywords to search for in company descriptions, names, etc."
922
+ )
923
+
924
+ q_organization_domains: Optional[List[str]] = Field(
925
+ default=None,
926
+ description="Specific company domains to search for, e.g. ['microsoft.com', 'google.com']."
927
+ )
928
+
929
+ # Company-specific filters
930
+ organization_ids: Optional[List[str]] = Field(
931
+ default=None,
932
+ description="Specific Apollo organization IDs to include."
933
+ )
934
+
935
+ not_organization_ids: Optional[List[str]] = Field(
936
+ default=None,
937
+ description="Apollo organization IDs to exclude from results."
938
+ )
939
+
940
+ # Search lists
941
+ q_organization_search_list_id: Optional[str] = Field(
942
+ default=None,
943
+ description="Include only organizations in a specific search list."
944
+ )
945
+
946
+ q_not_organization_search_list_id: Optional[str] = Field(
947
+ default=None,
948
+ description="Exclude organizations in a specific search list."
949
+ )
950
+
951
+ # Sorting
952
+ sort_by_field: Optional[str] = Field(
953
+ default=None,
954
+ description="Sort field, e.g. 'name', 'employee_count', 'last_updated', etc."
955
+ )
956
+
957
+ sort_ascending: Optional[bool] = Field(
958
+ default=None,
959
+ description="Sort ascending (True) or descending (False)."
960
+ )
961
+
962
+ # Additional filters that might be useful
963
+ organization_founded_year_min: Optional[int] = Field(
964
+ default=None,
965
+ description="Minimum founding year for the organization."
966
+ )
967
+
968
+ organization_founded_year_max: Optional[int] = Field(
969
+ default=None,
970
+ description="Maximum founding year for the organization."
971
+ )