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.
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/PKG-INFO +1 -1
- dhisana-0.0.1.dev257/README.md +257 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/setup.py +1 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/schemas/common.py +13 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/schemas/sales.py +233 -24
- dhisana-0.0.1.dev257/src/dhisana/utils/apollo_tools.py +1728 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/built_with_api_tools.py +4 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/cache_output_tools.py +22 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_email_validity_tools.py +39 -21
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_linkedin_url_validity.py +34 -6
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/clay_tools.py +3 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_search_query.py +7 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/dataframe_tools.py +2 -2
- dhisana-0.0.1.dev257/src/dhisana/utils/email_body_utils.py +72 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/email_provider.py +375 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/enrich_lead_information.py +180 -48
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/fetch_openai_config.py +9 -3
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_content.py +3 -1
- dhisana-0.0.1.dev257/src/dhisana/utils/generate_custom_message.py +271 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_email.py +66 -15
- dhisana-0.0.1.dev257/src/dhisana/utils/generate_email_response.py +480 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_linkedin_connect_message.py +9 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_linkedin_response_message.py +137 -73
- dhisana-0.0.1.dev257/src/dhisana/utils/generate_structured_output_internal.py +462 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/google_custom_search.py +267 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/google_oauth_tools.py +727 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/google_workspace_tools.py +312 -57
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/hubspot_clearbit.py +3 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/hubspot_crm_tools.py +718 -272
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/instantly_tools.py +3 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/lusha_tools.py +8 -3
- dhisana-0.0.1.dev257/src/dhisana/utils/mailgun_tools.py +156 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/mailreach_tools.py +123 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/microsoft365_tools.py +455 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openai_assistant_and_file_utils.py +3 -3
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openai_helpers.py +6 -4
- dhisana-0.0.1.dev257/src/dhisana/utils/profile.py +37 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/proxy_curl_tools.py +382 -77
- dhisana-0.0.1.dev257/src/dhisana/utils/proxycurl_search_leads.py +426 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/research_lead.py +3 -3
- dhisana-0.0.1.dev257/src/dhisana/utils/salesforce_crm_tools.py +477 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/search_router.py +131 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/search_router_jobs.py +51 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/sendgrid_tools.py +162 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/serarch_router_local_business.py +75 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/serpapi_additional_tools.py +290 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/serpapi_google_jobs.py +117 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/serpapi_google_search.py +188 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/serpapi_local_business_search.py +129 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/serpapi_search_tools.py +353 -424
- dhisana-0.0.1.dev257/src/dhisana/utils/serperdev_google_jobs.py +125 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/serperdev_local_business.py +154 -0
- dhisana-0.0.1.dev257/src/dhisana/utils/serperdev_search.py +233 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/smtp_email_tools.py +183 -15
- dhisana-0.0.1.dev257/src/dhisana/utils/test_connect.py +2212 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/trasform_json.py +2 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/zoominfo_tools.py +2 -2
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/test.py +1 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/PKG-INFO +1 -1
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/SOURCES.txt +31 -1
- dhisana-0.0.1.dev257/tests/test_apollo_company_search.py +260 -0
- dhisana-0.0.1.dev257/tests/test_apollo_lead_search.py +127 -0
- dhisana-0.0.1.dev257/tests/test_connectivity.py +118 -0
- dhisana-0.0.1.dev257/tests/test_email_body_utils.py +23 -0
- dhisana-0.0.1.dev257/tests/test_google_document.py +119 -0
- dhisana-0.0.1.dev257/tests/test_hubspot_call_logs.py +79 -0
- dhisana-0.0.1.dev257/tests/test_linkedin_serper.py +55 -0
- dhisana-0.0.1.dev257/tests/test_mailreach.py +179 -0
- dhisana-0.0.1.dev257/tests/test_mcp_connectivity.py +28 -0
- dhisana-0.0.1.dev257/tests/test_proxycurl_get_company_search_id.py +170 -0
- dhisana-0.0.1.dev257/tests/test_proxycurl_job_count.py +61 -0
- dhisana-0.0.1.dev257/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/apollo_tools.py +0 -962
- 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.dev257}/pyproject.toml +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/setup.cfg +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/cli.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/datasets.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/models.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/cli/predictions.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/schemas/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/ui/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/ui/components.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/add_mapping.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/agent_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/assistant_tool_tag.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/cache_output_tools_local.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/check_for_intent_signal.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/clean_properties.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/company_utils.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_salesnav_query.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/composite_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/domain_parser.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/email_parse_helpers.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/field_validators.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/g2_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_flow.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/linkedin_crawler.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/python_function_to_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/web_download_parse_tools.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/utils/workflow_code_model.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/__init__.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/agent.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/flow.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana/workflow/task.py +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/dependency_links.txt +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/entry_points.txt +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/requires.txt +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/src/dhisana.egg-info/top_level.txt +0 -0
- {dhisana-0.0.1.dev121 → dhisana-0.0.1.dev257}/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,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[
|
|
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):
|
|
@@ -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,
|
|
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,
|
|
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[
|
|
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=
|
|
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
|
|
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=
|
|
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
|
+
)
|