dhisana 0.0.1.dev121__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.
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/PKG-INFO +1 -1
- dhisana-0.0.1.dev231/README.md +257 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/setup.py +1 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/schemas/common.py +9 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/schemas/sales.py +200 -21
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/apollo_tools.py +736 -114
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/built_with_api_tools.py +4 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/check_email_validity_tools.py +35 -17
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/check_linkedin_url_validity.py +34 -6
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/clay_tools.py +3 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/compose_search_query.py +7 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/dataframe_tools.py +2 -2
- dhisana-0.0.1.dev231/src/dhisana/utils/email_body_utils.py +72 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/email_provider.py +375 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/enrich_lead_information.py +162 -46
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/fetch_openai_config.py +9 -3
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_email.py +10 -2
- dhisana-0.0.1.dev231/src/dhisana/utils/generate_email_response.py +465 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_linkedin_connect_message.py +9 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_linkedin_response_message.py +137 -73
- dhisana-0.0.1.dev231/src/dhisana/utils/generate_structured_output_internal.py +462 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/google_custom_search.py +267 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/google_oauth_tools.py +675 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/google_workspace_tools.py +192 -11
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/hubspot_clearbit.py +3 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/hubspot_crm_tools.py +718 -272
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/instantly_tools.py +3 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/lusha_tools.py +8 -3
- dhisana-0.0.1.dev231/src/dhisana/utils/mailgun_tools.py +150 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/microsoft365_tools.py +407 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/openai_assistant_and_file_utils.py +3 -3
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/openai_helpers.py +6 -4
- dhisana-0.0.1.dev231/src/dhisana/utils/profile.py +37 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/proxy_curl_tools.py +298 -60
- dhisana-0.0.1.dev231/src/dhisana/utils/proxycurl_search_leads.py +426 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/research_lead.py +3 -3
- dhisana-0.0.1.dev231/src/dhisana/utils/salesforce_crm_tools.py +477 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/search_router.py +131 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/search_router_jobs.py +51 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/sendgrid_tools.py +152 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/serarch_router_local_business.py +75 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/serpapi_additional_tools.py +290 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/serpapi_google_jobs.py +117 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/serpapi_google_search.py +188 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/serpapi_local_business_search.py +129 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/serpapi_search_tools.py +351 -422
- dhisana-0.0.1.dev231/src/dhisana/utils/serperdev_google_jobs.py +125 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/serperdev_local_business.py +154 -0
- dhisana-0.0.1.dev231/src/dhisana/utils/serperdev_search.py +233 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/smtp_email_tools.py +74 -5
- dhisana-0.0.1.dev231/src/dhisana/utils/test_connect.py +1669 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/trasform_json.py +2 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/zoominfo_tools.py +2 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/workflow/test.py +1 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/PKG-INFO +1 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/SOURCES.txt +28 -1
- dhisana-0.0.1.dev231/tests/test_apollo_company_search.py +216 -0
- dhisana-0.0.1.dev231/tests/test_apollo_lead_search.py +119 -0
- dhisana-0.0.1.dev231/tests/test_connectivity.py +102 -0
- dhisana-0.0.1.dev231/tests/test_email_body_utils.py +23 -0
- dhisana-0.0.1.dev231/tests/test_google_document.py +119 -0
- dhisana-0.0.1.dev231/tests/test_hubspot_call_logs.py +79 -0
- dhisana-0.0.1.dev231/tests/test_linkedin_serper.py +55 -0
- dhisana-0.0.1.dev231/tests/test_mcp_connectivity.py +28 -0
- dhisana-0.0.1.dev231/tests/test_proxycurl_get_company_search_id.py +170 -0
- dhisana-0.0.1.dev231/tests/test_proxycurl_job_count.py +61 -0
- dhisana-0.0.1.dev231/tests/test_structured_output_with_mcp.py +56 -0
- dhisana-0.0.1.dev121/README.md +0 -141
- dhisana-0.0.1.dev121/src/dhisana/utils/email_provider.py +0 -235
- dhisana-0.0.1.dev121/src/dhisana/utils/generate_email_response.py +0 -305
- dhisana-0.0.1.dev121/src/dhisana/utils/generate_structured_output_internal.py +0 -255
- dhisana-0.0.1.dev121/src/dhisana/utils/google_custom_search.py +0 -161
- dhisana-0.0.1.dev121/src/dhisana/utils/salesforce_crm_tools.py +0 -204
- dhisana-0.0.1.dev121/src/dhisana/utils/sendgrid_tools.py +0 -117
- dhisana-0.0.1.dev121/src/dhisana/utils/test_connect.py +0 -543
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/pyproject.toml +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/setup.cfg +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/cli/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/cli/cli.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/cli/datasets.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/cli/models.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/cli/predictions.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/schemas/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/ui/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/ui/components.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/add_mapping.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/agent_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/assistant_tool_tag.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/cache_output_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/cache_output_tools_local.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/check_for_intent_signal.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/clean_properties.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/company_utils.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/compose_salesnav_query.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/composite_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/domain_parser.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/email_parse_helpers.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/field_validators.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/g2_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_content.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_flow.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/linkedin_crawler.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/python_function_to_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/web_download_parse_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/utils/workflow_code_model.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/workflow/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/workflow/agent.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/workflow/flow.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana/workflow/task.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/dependency_links.txt +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/entry_points.txt +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/requires.txt +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/src/dhisana.egg-info/top_level.txt +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev231}/tests/test_agent_tools.py +0 -0
|
@@ -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
|
+
```
|
|
@@ -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
|
|
@@ -386,4 +393,5 @@ class ReplyEmailContext(BaseModel):
|
|
|
386
393
|
sender_email: str
|
|
387
394
|
sender_name: str
|
|
388
395
|
mark_as_read: str = "True"
|
|
389
|
-
add_labels: Optional[List[str]] = None
|
|
396
|
+
add_labels: Optional[List[str]] = None
|
|
397
|
+
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[
|
|
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
|
-
|
|
30
|
-
engaged:
|
|
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
|
-
|
|
37
|
-
] = None
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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):
|
|
@@ -242,6 +294,7 @@ class MessageGenerationInstructions(BaseModel):
|
|
|
242
294
|
"""
|
|
243
295
|
instructions_to_generate_message: Optional[str] = None
|
|
244
296
|
prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
|
|
297
|
+
use_cache: Optional[bool] = True
|
|
245
298
|
|
|
246
299
|
class CampaignContext(BaseModel):
|
|
247
300
|
"""
|
|
@@ -303,6 +356,7 @@ class MessageItem(BaseModel):
|
|
|
303
356
|
...,
|
|
304
357
|
description="Body of the message in plain text"
|
|
305
358
|
)
|
|
359
|
+
html_body: Optional[str] = None
|
|
306
360
|
|
|
307
361
|
class MessageResponse(BaseModel):
|
|
308
362
|
"""
|
|
@@ -438,14 +492,14 @@ class HubSpotLeadInformation(BaseModel):
|
|
|
438
492
|
organization_name: str = Field("", description="Current Company where lead works")
|
|
439
493
|
organization_website: str = Field("", description="Current Company website of the lead")
|
|
440
494
|
organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
|
|
441
|
-
additional_properties: Optional[Dict[str,
|
|
495
|
+
additional_properties: Optional[Dict[str, Any]] = None
|
|
442
496
|
|
|
443
497
|
class HubSpotCompanyinformation(BaseModel):
|
|
444
498
|
primary_domain_of_organization: str = Field("", description="Primary domain of the organization")
|
|
445
499
|
organization_name: str = Field("", description="Current Company where lead works")
|
|
446
500
|
organization_website: str = Field("", description="Current Company website of the lead")
|
|
447
501
|
organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
|
|
448
|
-
additional_properties: Optional[Dict[str,
|
|
502
|
+
additional_properties: Optional[Dict[str, Any]] = None
|
|
449
503
|
|
|
450
504
|
|
|
451
505
|
# --------------------------------------------------------------------
|
|
@@ -462,6 +516,7 @@ HUBSPOT_TO_LEAD_MAPPING = {
|
|
|
462
516
|
"address": "lead_location", # You can choose "city", "state", etc. if you prefer
|
|
463
517
|
"city": "lead_location",
|
|
464
518
|
"domain": "primary_domain_of_organization",
|
|
519
|
+
"hs_linkedin_url": "user_linkedin_url",
|
|
465
520
|
}
|
|
466
521
|
|
|
467
522
|
class SmartListStatus(str, Enum):
|
|
@@ -482,6 +537,11 @@ class SmartListSourceType(str, Enum):
|
|
|
482
537
|
GOOGLE_SHEETS = "GOOGLE_SHEETS"
|
|
483
538
|
CUSTOM_WEBSITE = "CUSTOM_WEBSITE"
|
|
484
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"
|
|
485
545
|
|
|
486
546
|
class SourceConfiguration(BaseModel):
|
|
487
547
|
"""
|
|
@@ -577,13 +637,18 @@ class SmartListLead(BaseModel):
|
|
|
577
637
|
organization_name: Optional[str] = None
|
|
578
638
|
organization_website: Optional[str] = None
|
|
579
639
|
summary_about_lead: Optional[str] = None
|
|
580
|
-
keywords: Optional[
|
|
640
|
+
keywords: Optional[Any] = None
|
|
581
641
|
additional_properties: Optional[Dict[str, Any]] = None
|
|
582
642
|
research_summary: Optional[str] = None
|
|
583
643
|
|
|
584
644
|
qualification_score: Optional[float] = None
|
|
585
645
|
qualification_reason: Optional[str] = None
|
|
586
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
|
|
587
652
|
|
|
588
653
|
agent_instance_id: Optional[UUID] = None
|
|
589
654
|
organization_id: Optional[UUID] = None
|
|
@@ -595,7 +660,6 @@ class SmartListLead(BaseModel):
|
|
|
595
660
|
revenue: Optional[str] = None
|
|
596
661
|
company_size: Optional[str] = None
|
|
597
662
|
industry: Optional[str] = None
|
|
598
|
-
|
|
599
663
|
class Config:
|
|
600
664
|
from_attributes = True
|
|
601
665
|
|
|
@@ -760,3 +824,118 @@ class LeadsQueryFilters(BaseModel):
|
|
|
760
824
|
description="Ranges for organization number of employees."
|
|
761
825
|
)
|
|
762
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
|
+
|