dhisana 0.0.1.dev243__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dhisana/__init__.py +1 -0
- dhisana/cli/__init__.py +1 -0
- dhisana/cli/cli.py +20 -0
- dhisana/cli/datasets.py +27 -0
- dhisana/cli/models.py +26 -0
- dhisana/cli/predictions.py +20 -0
- dhisana/schemas/__init__.py +1 -0
- dhisana/schemas/common.py +399 -0
- dhisana/schemas/sales.py +965 -0
- dhisana/ui/__init__.py +1 -0
- dhisana/ui/components.py +472 -0
- dhisana/utils/__init__.py +1 -0
- dhisana/utils/add_mapping.py +352 -0
- dhisana/utils/agent_tools.py +51 -0
- dhisana/utils/apollo_tools.py +1597 -0
- dhisana/utils/assistant_tool_tag.py +4 -0
- dhisana/utils/built_with_api_tools.py +282 -0
- dhisana/utils/cache_output_tools.py +98 -0
- dhisana/utils/cache_output_tools_local.py +78 -0
- dhisana/utils/check_email_validity_tools.py +717 -0
- dhisana/utils/check_for_intent_signal.py +107 -0
- dhisana/utils/check_linkedin_url_validity.py +209 -0
- dhisana/utils/clay_tools.py +43 -0
- dhisana/utils/clean_properties.py +135 -0
- dhisana/utils/company_utils.py +60 -0
- dhisana/utils/compose_salesnav_query.py +259 -0
- dhisana/utils/compose_search_query.py +759 -0
- dhisana/utils/compose_three_step_workflow.py +234 -0
- dhisana/utils/composite_tools.py +137 -0
- dhisana/utils/dataframe_tools.py +237 -0
- dhisana/utils/domain_parser.py +45 -0
- dhisana/utils/email_body_utils.py +72 -0
- dhisana/utils/email_parse_helpers.py +132 -0
- dhisana/utils/email_provider.py +375 -0
- dhisana/utils/enrich_lead_information.py +933 -0
- dhisana/utils/extract_email_content_for_llm.py +101 -0
- dhisana/utils/fetch_openai_config.py +129 -0
- dhisana/utils/field_validators.py +426 -0
- dhisana/utils/g2_tools.py +104 -0
- dhisana/utils/generate_content.py +41 -0
- dhisana/utils/generate_custom_message.py +271 -0
- dhisana/utils/generate_email.py +278 -0
- dhisana/utils/generate_email_response.py +465 -0
- dhisana/utils/generate_flow.py +102 -0
- dhisana/utils/generate_leads_salesnav.py +303 -0
- dhisana/utils/generate_linkedin_connect_message.py +224 -0
- dhisana/utils/generate_linkedin_response_message.py +317 -0
- dhisana/utils/generate_structured_output_internal.py +462 -0
- dhisana/utils/google_custom_search.py +267 -0
- dhisana/utils/google_oauth_tools.py +727 -0
- dhisana/utils/google_workspace_tools.py +1294 -0
- dhisana/utils/hubspot_clearbit.py +96 -0
- dhisana/utils/hubspot_crm_tools.py +2440 -0
- dhisana/utils/instantly_tools.py +149 -0
- dhisana/utils/linkedin_crawler.py +168 -0
- dhisana/utils/lusha_tools.py +333 -0
- dhisana/utils/mailgun_tools.py +156 -0
- dhisana/utils/mailreach_tools.py +123 -0
- dhisana/utils/microsoft365_tools.py +455 -0
- dhisana/utils/openai_assistant_and_file_utils.py +267 -0
- dhisana/utils/openai_helpers.py +977 -0
- dhisana/utils/openapi_spec_to_tools.py +45 -0
- dhisana/utils/openapi_tool/__init__.py +1 -0
- dhisana/utils/openapi_tool/api_models.py +633 -0
- dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +271 -0
- dhisana/utils/openapi_tool/openapi_tool.py +319 -0
- dhisana/utils/parse_linkedin_messages_txt.py +100 -0
- dhisana/utils/profile.py +37 -0
- dhisana/utils/proxy_curl_tools.py +1226 -0
- dhisana/utils/proxycurl_search_leads.py +426 -0
- dhisana/utils/python_function_to_tools.py +83 -0
- dhisana/utils/research_lead.py +176 -0
- dhisana/utils/sales_navigator_crawler.py +1103 -0
- dhisana/utils/salesforce_crm_tools.py +477 -0
- dhisana/utils/search_router.py +131 -0
- dhisana/utils/search_router_jobs.py +51 -0
- dhisana/utils/sendgrid_tools.py +162 -0
- dhisana/utils/serarch_router_local_business.py +75 -0
- dhisana/utils/serpapi_additional_tools.py +290 -0
- dhisana/utils/serpapi_google_jobs.py +117 -0
- dhisana/utils/serpapi_google_search.py +188 -0
- dhisana/utils/serpapi_local_business_search.py +129 -0
- dhisana/utils/serpapi_search_tools.py +852 -0
- dhisana/utils/serperdev_google_jobs.py +125 -0
- dhisana/utils/serperdev_local_business.py +154 -0
- dhisana/utils/serperdev_search.py +233 -0
- dhisana/utils/smtp_email_tools.py +582 -0
- dhisana/utils/test_connect.py +2087 -0
- dhisana/utils/trasform_json.py +173 -0
- dhisana/utils/web_download_parse_tools.py +189 -0
- dhisana/utils/workflow_code_model.py +5 -0
- dhisana/utils/zoominfo_tools.py +357 -0
- dhisana/workflow/__init__.py +1 -0
- dhisana/workflow/agent.py +18 -0
- dhisana/workflow/flow.py +44 -0
- dhisana/workflow/task.py +43 -0
- dhisana/workflow/test.py +90 -0
- dhisana-0.0.1.dev243.dist-info/METADATA +43 -0
- dhisana-0.0.1.dev243.dist-info/RECORD +102 -0
- dhisana-0.0.1.dev243.dist-info/WHEEL +5 -0
- dhisana-0.0.1.dev243.dist-info/entry_points.txt +2 -0
- dhisana-0.0.1.dev243.dist-info/top_level.txt +1 -0
dhisana/schemas/sales.py
ADDED
|
@@ -0,0 +1,965 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
from pydantic import BaseModel, Field, field_validator
|
|
5
|
+
from typing import List, Optional, Dict, Any
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Optional, List, Dict, Literal
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# -----------------------------
|
|
11
|
+
# Lead-List-Specific Schemas
|
|
12
|
+
# -----------------------------
|
|
13
|
+
|
|
14
|
+
class Lead(BaseModel):
|
|
15
|
+
id: Optional[UUID] = None
|
|
16
|
+
full_name: Optional[str] = None
|
|
17
|
+
first_name: Optional[str] = None
|
|
18
|
+
last_name: Optional[str] = None
|
|
19
|
+
email: Optional[str] = None
|
|
20
|
+
user_linkedin_url: Optional[str] = None
|
|
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
|
|
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
|
|
29
|
+
job_title: Optional[str] = None
|
|
30
|
+
phone: Optional[str] = None
|
|
31
|
+
headline: Optional[str] = None
|
|
32
|
+
lead_location: Optional[str] = None
|
|
33
|
+
organization_name: Optional[str] = None
|
|
34
|
+
organization_website: Optional[str] = None
|
|
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]] = {}
|
|
47
|
+
workflow_stage: Optional[str] = None
|
|
48
|
+
|
|
49
|
+
engaged: bool = False
|
|
50
|
+
last_contact: Optional[int] = None
|
|
51
|
+
research_summary: Optional[str] = None
|
|
52
|
+
task_ids: Optional[List[str]] = 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)]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class LeadList(BaseModel):
|
|
102
|
+
id: Optional[str] = None
|
|
103
|
+
name: str
|
|
104
|
+
sources: List[str]
|
|
105
|
+
tags: List[str]
|
|
106
|
+
category: str
|
|
107
|
+
leads_count: int
|
|
108
|
+
assigned_users: List[str]
|
|
109
|
+
updated_at: int
|
|
110
|
+
status: Literal["connected", "disconnected", "coming soon"]
|
|
111
|
+
leads: Optional[List[Lead]] = None
|
|
112
|
+
public: Optional[bool] = None
|
|
113
|
+
|
|
114
|
+
# -----------------------------
|
|
115
|
+
# Task-Specific Schemas
|
|
116
|
+
# -----------------------------
|
|
117
|
+
|
|
118
|
+
class TaskStatus(str, Enum):
|
|
119
|
+
PENDING = "PENDING"
|
|
120
|
+
RUNNING = "RUNNING"
|
|
121
|
+
FAILED = "FAILED"
|
|
122
|
+
COMPLETED = "COMPLETED"
|
|
123
|
+
|
|
124
|
+
class TaskBase(BaseModel):
|
|
125
|
+
name: str
|
|
126
|
+
task_type: str
|
|
127
|
+
data_id: Optional[UUID] = None
|
|
128
|
+
data_type: Optional[str] = None
|
|
129
|
+
|
|
130
|
+
inputs: Optional[List[Dict[str, Any]]] = []
|
|
131
|
+
outputs: Optional[List[Dict[str, Any]]] = []
|
|
132
|
+
|
|
133
|
+
class TaskCreate(TaskBase):
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
class TaskUpdate(BaseModel):
|
|
137
|
+
status: Optional[TaskStatus] = None
|
|
138
|
+
logs: Optional[List[Any]] = None
|
|
139
|
+
metrics: Optional[Dict[str, Any]] = None
|
|
140
|
+
outputs: Optional[List[Dict[str, Any]]] = None
|
|
141
|
+
|
|
142
|
+
class Task(TaskBase):
|
|
143
|
+
id: UUID
|
|
144
|
+
status: TaskStatus
|
|
145
|
+
logs: List[Any] = []
|
|
146
|
+
metrics: Dict[str, Any] = {}
|
|
147
|
+
created_at: int # store as ms since epoch
|
|
148
|
+
updated_at: int
|
|
149
|
+
completed_at: Optional[int] = None
|
|
150
|
+
|
|
151
|
+
class Config:
|
|
152
|
+
from_attributes = True
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# -----------------------------
|
|
156
|
+
# Campaign-Specific Schemas
|
|
157
|
+
# -----------------------------
|
|
158
|
+
|
|
159
|
+
class SendRules(BaseModel):
|
|
160
|
+
daily_send_limit: Optional[int] = None
|
|
161
|
+
concurrency_limit: Optional[int] = None
|
|
162
|
+
time_window_start: Optional[str] = None # "HH:MM" string
|
|
163
|
+
time_window_end: Optional[str] = None
|
|
164
|
+
block_weekends: Optional[bool] = False
|
|
165
|
+
|
|
166
|
+
class Touch(BaseModel):
|
|
167
|
+
type: str # e.g. 'email', 'linkedin', ...
|
|
168
|
+
action: str # e.g. 'view_linkedin_profile', 'send_connection_request'
|
|
169
|
+
details: str
|
|
170
|
+
delay_days: int
|
|
171
|
+
template_id: Optional[str] = None
|
|
172
|
+
|
|
173
|
+
class PromptEngineeringGuidance(BaseModel):
|
|
174
|
+
tone: str
|
|
175
|
+
word_count: int
|
|
176
|
+
paragraphs: int
|
|
177
|
+
|
|
178
|
+
class LeadLog(BaseModel):
|
|
179
|
+
id: Optional[str] = None
|
|
180
|
+
message: str
|
|
181
|
+
channel: Optional[str] = None
|
|
182
|
+
timestamp: int # ms since epoch
|
|
183
|
+
status: Optional[str] = None
|
|
184
|
+
|
|
185
|
+
class CampaignLead(BaseModel):
|
|
186
|
+
id: Optional[str] = None
|
|
187
|
+
campaign_id: str
|
|
188
|
+
lead_list_id: Optional[str] = None
|
|
189
|
+
lead_id: Optional[str] = None
|
|
190
|
+
lead_name: str
|
|
191
|
+
|
|
192
|
+
status: Optional[str] = None # 'PENDING', 'WAITING_APPROVAL', 'OUTBOUND_PENDING', 'COMPLETED'
|
|
193
|
+
current_step: Optional[int] = 0
|
|
194
|
+
total_steps: Optional[int] = 0
|
|
195
|
+
engaged: Optional[bool] = False
|
|
196
|
+
last_touch: Optional[str] = None
|
|
197
|
+
created_at: Optional[int] = None # ms since epoch
|
|
198
|
+
updated_at: Optional[int] = None
|
|
199
|
+
|
|
200
|
+
logs: Optional[List[LeadLog]] = None
|
|
201
|
+
|
|
202
|
+
class CampaignCounter(BaseModel):
|
|
203
|
+
id: Optional[str] = None
|
|
204
|
+
campaign_id: str
|
|
205
|
+
date: str # "YYYY-MM-DD"
|
|
206
|
+
daily_sends: int
|
|
207
|
+
current_concurrency: int
|
|
208
|
+
|
|
209
|
+
class CampaignStatus(str, Enum):
|
|
210
|
+
DRAFT = "DRAFT"
|
|
211
|
+
ACTIVE = "ACTIVE"
|
|
212
|
+
PAUSED = "PAUSED"
|
|
213
|
+
COMPLETED = "COMPLETED"
|
|
214
|
+
|
|
215
|
+
class PendingEvent(BaseModel):
|
|
216
|
+
event_id: str
|
|
217
|
+
lead_id: str
|
|
218
|
+
touch_index: int
|
|
219
|
+
channel: str
|
|
220
|
+
action: str
|
|
221
|
+
subject: str
|
|
222
|
+
message: str
|
|
223
|
+
created_at: int # ms since epoch
|
|
224
|
+
|
|
225
|
+
class Campaign(BaseModel):
|
|
226
|
+
id: str
|
|
227
|
+
name: str
|
|
228
|
+
description: str
|
|
229
|
+
lead_lists: List[str]
|
|
230
|
+
run_mode: str
|
|
231
|
+
updated_at: int # ms since epoch
|
|
232
|
+
|
|
233
|
+
tags: Optional[List[str]] = None
|
|
234
|
+
channel: Optional[str] = None
|
|
235
|
+
mission_objective: Optional[str] = None
|
|
236
|
+
mission_progress: Optional[int] = None
|
|
237
|
+
ai_alerts: Optional[List[str]] = None
|
|
238
|
+
automatic_adjustments: Optional[List[str]] = None
|
|
239
|
+
|
|
240
|
+
product_name: Optional[str] = None
|
|
241
|
+
value_prop: Optional[str] = None
|
|
242
|
+
call_to_action: Optional[str] = None
|
|
243
|
+
pain_points: Optional[List[str]] = None
|
|
244
|
+
proof_points: Optional[List[str]] = None
|
|
245
|
+
prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
|
|
246
|
+
prompt_templates: Optional[List[Dict[str, Any]]] = None
|
|
247
|
+
touches: Optional[List[Touch]] = None
|
|
248
|
+
send_rules: Optional[SendRules] = None
|
|
249
|
+
|
|
250
|
+
status: Optional[CampaignStatus] = None
|
|
251
|
+
start_date: Optional[int] = None # ms since epoch
|
|
252
|
+
pause_date: Optional[int] = None
|
|
253
|
+
end_date: Optional[int] = None
|
|
254
|
+
|
|
255
|
+
leads: Optional[List[CampaignLead]] = None
|
|
256
|
+
counter: Optional[CampaignCounter] = None
|
|
257
|
+
pending_events: Optional[List[PendingEvent]] = None
|
|
258
|
+
|
|
259
|
+
class Config:
|
|
260
|
+
from_attributes = True
|
|
261
|
+
|
|
262
|
+
# ---------------------------------------------------------------------
|
|
263
|
+
# New Classes with Comments
|
|
264
|
+
# ---------------------------------------------------------------------
|
|
265
|
+
class ChannelType(str, Enum):
|
|
266
|
+
"""
|
|
267
|
+
Enumerates the different communication channels.
|
|
268
|
+
"""
|
|
269
|
+
NEW_EMAIL = "new_email"
|
|
270
|
+
LINKEDIN_CONNECT_MESSAGE = "linkedin_connect_message"
|
|
271
|
+
REPLY_EMAIL = "reply_email"
|
|
272
|
+
LINKEDIN_USER_MESSAGE = "linkedin_user_message"
|
|
273
|
+
CUSTOM_MESSAGE = "custom_message"
|
|
274
|
+
|
|
275
|
+
class SenderInfo(BaseModel):
|
|
276
|
+
"""
|
|
277
|
+
Holds information about the sender:
|
|
278
|
+
- sender_full_name: Full name of the sender.
|
|
279
|
+
- sender_first_name: Sender's first name.
|
|
280
|
+
- sender_last_name: Sender's last name.
|
|
281
|
+
- sender_bio: Optional biography or short description of the sender.
|
|
282
|
+
"""
|
|
283
|
+
sender_full_name: Optional[str] = None
|
|
284
|
+
sender_first_name: Optional[str] = None
|
|
285
|
+
sender_last_name: Optional[str] = None
|
|
286
|
+
sender_email: Optional[str] = None
|
|
287
|
+
sender_bio: Optional[str] = None
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class MessageGenerationInstructions(BaseModel):
|
|
291
|
+
"""
|
|
292
|
+
Holds the user-supplied instructions for generating the message:
|
|
293
|
+
- instructions_to_generate_message: Plain text or template instructions from the user.
|
|
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.
|
|
297
|
+
"""
|
|
298
|
+
instructions_to_generate_message: Optional[str] = None
|
|
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
|
|
303
|
+
|
|
304
|
+
class CampaignContext(BaseModel):
|
|
305
|
+
"""
|
|
306
|
+
Represents the context of the campaign or marketing effort:
|
|
307
|
+
- product_name: Name of the product or service.
|
|
308
|
+
- value_prop: Value proposition of the product.
|
|
309
|
+
- call_to_action: Suggested CTA for the user to take.
|
|
310
|
+
- pain_points: List of known pain points for the lead or market.
|
|
311
|
+
- proof_points: List of proof points or social proof for the product.
|
|
312
|
+
- email_triage_guidelines: Guidelines for triaging or responding to emails.
|
|
313
|
+
- linkedin_triage_guidelines: Guidelines for triaging or responding to LinkedIn messages.
|
|
314
|
+
"""
|
|
315
|
+
product_name: Optional[str] = None
|
|
316
|
+
value_prop: Optional[str] = None
|
|
317
|
+
call_to_action: Optional[str] = None
|
|
318
|
+
pain_points: Optional[List[str]] = None
|
|
319
|
+
proof_points: Optional[List[str]] = None
|
|
320
|
+
email_triage_guidelines: Optional[str] = None
|
|
321
|
+
linkedin_triage_guidelines: Optional[str] = None
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class MessageItem(BaseModel):
|
|
325
|
+
"""
|
|
326
|
+
Represents a single message item in a conversation.
|
|
327
|
+
"""
|
|
328
|
+
message_id: str = Field(
|
|
329
|
+
...,
|
|
330
|
+
description="Unique identifier for the message"
|
|
331
|
+
)
|
|
332
|
+
thread_id: str = Field(
|
|
333
|
+
...,
|
|
334
|
+
description="Unique identifier for the conversation thread"
|
|
335
|
+
)
|
|
336
|
+
sender_name: str = Field(
|
|
337
|
+
...,
|
|
338
|
+
description="Sender's display name (if available)"
|
|
339
|
+
)
|
|
340
|
+
sender_email: str = Field(
|
|
341
|
+
...,
|
|
342
|
+
description="Sender's email address"
|
|
343
|
+
)
|
|
344
|
+
receiver_name: str = Field(
|
|
345
|
+
...,
|
|
346
|
+
description="Comma-separated list of receiver names"
|
|
347
|
+
)
|
|
348
|
+
receiver_email: str = Field(
|
|
349
|
+
...,
|
|
350
|
+
description="Comma-separated list of receiver emails"
|
|
351
|
+
)
|
|
352
|
+
iso_datetime: str = Field(
|
|
353
|
+
...,
|
|
354
|
+
description="Date/time of the message in ISO 8601 format"
|
|
355
|
+
)
|
|
356
|
+
subject: str = Field(
|
|
357
|
+
...,
|
|
358
|
+
description="Subject of the message"
|
|
359
|
+
)
|
|
360
|
+
body: str = Field(
|
|
361
|
+
...,
|
|
362
|
+
description="Body of the message in plain text"
|
|
363
|
+
)
|
|
364
|
+
html_body: Optional[str] = None
|
|
365
|
+
|
|
366
|
+
class MessageResponse(BaseModel):
|
|
367
|
+
"""
|
|
368
|
+
Model representing the structured response for a LinkedIn conversation triage.
|
|
369
|
+
- triage_status: "AUTOMATIC" or "REQUIRES_APPROVAL"
|
|
370
|
+
- triage_reason: Optional reason text if triage_status == "REQUIRES_APPROVAL"
|
|
371
|
+
- response_action_to_take: The recommended next action (e.g., SEND_REPLY, WAIT_TO_SEND, STOP_SENDING, etc.)
|
|
372
|
+
- message_item: The actual message to be sent or used for approval.
|
|
373
|
+
"""
|
|
374
|
+
triage_status: str # "AUTOMATIC" or "REQUIRES_APPROVAL"
|
|
375
|
+
triage_reason: Optional[str]
|
|
376
|
+
response_action_to_take: str
|
|
377
|
+
message_item: MessageItem
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class ConversationContext(BaseModel):
|
|
381
|
+
"""
|
|
382
|
+
Contains the current conversation threads for email or LinkedIn:
|
|
383
|
+
- current_email_thread: Existing email thread if any.
|
|
384
|
+
- current_linkedin_thread: Existing LinkedIn thread if any.
|
|
385
|
+
"""
|
|
386
|
+
current_email_thread: Optional[List[MessageItem]] = None
|
|
387
|
+
current_linkedin_thread: Optional[List[MessageItem]] = None
|
|
388
|
+
|
|
389
|
+
class ExternalDataSources(BaseModel):
|
|
390
|
+
"""
|
|
391
|
+
Holds references to external or third-party data integrations:
|
|
392
|
+
- external_openai_vector_store_id: ID for a vector store used for context retrieval.
|
|
393
|
+
"""
|
|
394
|
+
external_openai_vector_store_id: Optional[str] = None
|
|
395
|
+
|
|
396
|
+
class ContentGenerationContext(BaseModel):
|
|
397
|
+
"""
|
|
398
|
+
Consolidates all relevant data needed for generating content:
|
|
399
|
+
1) campaign_context: Details about the current campaign or marketing approach.
|
|
400
|
+
2) lead_info: The lead's basic information.
|
|
401
|
+
3) sender_info: Who is sending the message.
|
|
402
|
+
4) external_known_data: Any references to external data sources (e.g., vector store IDs).
|
|
403
|
+
5) current_conversation_context: Current or ongoing conversation threads (email or LinkedIn).
|
|
404
|
+
6) target_channel_type: Which channel we are generating content for (email, LinkedIn, etc.).
|
|
405
|
+
"""
|
|
406
|
+
campaign_context: Optional[CampaignContext] = None
|
|
407
|
+
lead_info: Optional[Lead] = None
|
|
408
|
+
sender_info: Optional[SenderInfo] = None
|
|
409
|
+
external_known_data: Optional[ExternalDataSources] = None
|
|
410
|
+
current_conversation_context: Optional[ConversationContext] = None
|
|
411
|
+
target_channel_type: Optional[ChannelType] = None
|
|
412
|
+
message_instructions: MessageGenerationInstructions = None
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
# -----------------------------
|
|
416
|
+
# TOUCHPOINT + EXECUTION
|
|
417
|
+
# -----------------------------
|
|
418
|
+
class TouchPointStatus(BaseModel):
|
|
419
|
+
"""
|
|
420
|
+
Holds the dynamic state of each lead’s progress in the campaign.
|
|
421
|
+
"""
|
|
422
|
+
is_connected_on_linkedin: bool
|
|
423
|
+
first_introduction_message_sent: bool
|
|
424
|
+
got_postive_response: bool
|
|
425
|
+
got_negative_response: bool
|
|
426
|
+
|
|
427
|
+
# Logging how many total messages or touches we’ve attempted.
|
|
428
|
+
messages_sent: int
|
|
429
|
+
|
|
430
|
+
# If the lead explicitly requested no further contact.
|
|
431
|
+
did_opt_out: bool
|
|
432
|
+
|
|
433
|
+
# Specific dispositions from the lead's response (e.g. "not_interested", "schedule_demo", etc.)
|
|
434
|
+
response_disposition: Optional[str] = None
|
|
435
|
+
|
|
436
|
+
# Maximum allowed attempts (touches)
|
|
437
|
+
max_touch_points: int
|
|
438
|
+
|
|
439
|
+
likely_to_engage_score: int
|
|
440
|
+
|
|
441
|
+
# Date/time fields
|
|
442
|
+
last_profile_viewed_date: Optional[str] = None
|
|
443
|
+
last_linkedin_message_sent_date: Optional[str] = None
|
|
444
|
+
last_email_sent_date: Optional[str] = None
|
|
445
|
+
last_email_response_received_date: Optional[str] = None
|
|
446
|
+
last_post_date: Optional[str] = None
|
|
447
|
+
last_linkedin_message_received_date: Optional[str] = None
|
|
448
|
+
|
|
449
|
+
# LinkedIn Connection fields
|
|
450
|
+
connection_status: Optional[str] = None # e.g., "connected", "pending"
|
|
451
|
+
connection_request_sent_date: Optional[str] = None
|
|
452
|
+
connection_degree: Optional[str] = None # "1st", "2nd", or "3rd"
|
|
453
|
+
|
|
454
|
+
# Additional fields we want to store
|
|
455
|
+
sdr_user_id: Optional[str] = None
|
|
456
|
+
user_linkedin_url: Optional[str] = None
|
|
457
|
+
user_linkedin_salesnav_url: Optional[str] = None
|
|
458
|
+
full_name: Optional[str] = None
|
|
459
|
+
first_name: Optional[str] = None
|
|
460
|
+
last_name: Optional[str] = None
|
|
461
|
+
location: Optional[str] = None
|
|
462
|
+
is_past_colleague: Optional[bool] = None
|
|
463
|
+
number_of_mutual_connections: Optional[int] = None
|
|
464
|
+
organization_name: Optional[str] = None
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
class LeadCampaignExecutionContext(BaseModel):
|
|
468
|
+
"""
|
|
469
|
+
This is the combined object passed to run_campaign_cadence_for_lead.
|
|
470
|
+
"""
|
|
471
|
+
campaign_context: Optional[CampaignContext] = None
|
|
472
|
+
lead_info: Optional[Lead] = None
|
|
473
|
+
sender_info: Optional[SenderInfo] = None
|
|
474
|
+
external_known_data: Optional[ExternalDataSources] = None
|
|
475
|
+
current_conversation_context: Optional[ConversationContext] = None
|
|
476
|
+
message_instructions: MessageGenerationInstructions = MessageGenerationInstructions()
|
|
477
|
+
touchpoint_status: Optional[TouchPointStatus] = None
|
|
478
|
+
current_user_id: Optional[str] = None
|
|
479
|
+
custom_instructions_for_cadence: Optional[str] = None
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
# --------------------------------------------------------------------
|
|
484
|
+
# 1. Define your HubSpotLeadInformation model
|
|
485
|
+
# --------------------------------------------------------------------
|
|
486
|
+
class HubSpotLeadInformation(BaseModel):
|
|
487
|
+
full_name: str = Field("", description="Full name of the lead")
|
|
488
|
+
first_name: str = Field("", description="First name of the lead")
|
|
489
|
+
last_name: str = Field("", description="Last name of the lead")
|
|
490
|
+
email: str = Field("", description="Email address of the lead")
|
|
491
|
+
user_linkedin_url: str = Field("", description="LinkedIn URL of the lead")
|
|
492
|
+
primary_domain_of_organization: str = Field("", description="Primary domain of the organization")
|
|
493
|
+
job_title: str = Field("", description="Job Title of the lead")
|
|
494
|
+
phone: str = Field("", description="Phone number of the lead")
|
|
495
|
+
headline: str = Field("", description="Headline of the lead")
|
|
496
|
+
lead_location: str = Field("", description="Location of the lead")
|
|
497
|
+
organization_name: str = Field("", description="Current Company where lead works")
|
|
498
|
+
organization_website: str = Field("", description="Current Company website of the lead")
|
|
499
|
+
organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
|
|
500
|
+
additional_properties: Optional[Dict[str, Any]] = None
|
|
501
|
+
|
|
502
|
+
class HubSpotCompanyinformation(BaseModel):
|
|
503
|
+
primary_domain_of_organization: str = Field("", description="Primary domain of the organization")
|
|
504
|
+
organization_name: str = Field("", description="Current Company where lead works")
|
|
505
|
+
organization_website: str = Field("", description="Current Company website of the lead")
|
|
506
|
+
organization_linkedin_url : str = Field("", description="Company LinkedIn URL")
|
|
507
|
+
additional_properties: Optional[Dict[str, Any]] = None
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
# --------------------------------------------------------------------
|
|
511
|
+
# 2. Map HubSpot property names -> HubSpotLeadInformation fields
|
|
512
|
+
# --------------------------------------------------------------------
|
|
513
|
+
HUBSPOT_TO_LEAD_MAPPING = {
|
|
514
|
+
"firstname": "first_name",
|
|
515
|
+
"lastname": "last_name",
|
|
516
|
+
"email": "email",
|
|
517
|
+
"phone": "phone",
|
|
518
|
+
"jobtitle": "job_title", # Default HubSpot job title property
|
|
519
|
+
"company": "organization_name", # Map "company" -> "organization_name"
|
|
520
|
+
"website": "organization_website", # Map "website" -> "organization_website"
|
|
521
|
+
"address": "lead_location", # You can choose "city", "state", etc. if you prefer
|
|
522
|
+
"city": "lead_location",
|
|
523
|
+
"domain": "primary_domain_of_organization",
|
|
524
|
+
"hs_linkedin_url": "user_linkedin_url",
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
class SmartListStatus(str, Enum):
|
|
528
|
+
DRAFT = "DRAFT"
|
|
529
|
+
ACTIVE = "ACTIVE"
|
|
530
|
+
COMPLETED = "COMPLETED"
|
|
531
|
+
|
|
532
|
+
class SmartListInputType(str, Enum):
|
|
533
|
+
LEADS = "LEADS"
|
|
534
|
+
ACCOUNTS = "ACCOUNTS"
|
|
535
|
+
|
|
536
|
+
class SmartListSourceType(str, Enum):
|
|
537
|
+
SALES_NAVIGATOR = "SALES_NAVIGATOR"
|
|
538
|
+
GOOGLE_SEARCH = "GOOGLE_SEARCH"
|
|
539
|
+
HUBSPOT = "HUBSPOT"
|
|
540
|
+
APOLLO = "APOLLO"
|
|
541
|
+
CSV = "CSV"
|
|
542
|
+
GOOGLE_SHEETS = "GOOGLE_SHEETS"
|
|
543
|
+
CUSTOM_WEBSITE = "CUSTOM_WEBSITE"
|
|
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"
|
|
550
|
+
|
|
551
|
+
class SourceConfiguration(BaseModel):
|
|
552
|
+
"""
|
|
553
|
+
Defines configuration details for each source type.
|
|
554
|
+
Depending on the source_type, only certain fields
|
|
555
|
+
may be required or used.
|
|
556
|
+
"""
|
|
557
|
+
# For Sales Navigator or Apollo or Google Search
|
|
558
|
+
search_query: Optional[str] = None
|
|
559
|
+
# For HubSpot
|
|
560
|
+
list_id: Optional[str] = None
|
|
561
|
+
list_name: Optional[str] = None
|
|
562
|
+
# For CSV
|
|
563
|
+
file_path: Optional[str] = None
|
|
564
|
+
# For Google Sheets
|
|
565
|
+
source_url: Optional[str] = None
|
|
566
|
+
# For Github
|
|
567
|
+
github_search_query: Optional[str] = None
|
|
568
|
+
github_max_repos: Optional[int] = None
|
|
569
|
+
github_max_contributors: Optional[int] = None
|
|
570
|
+
|
|
571
|
+
# Custom website inputs
|
|
572
|
+
custom_instructions_for_doing_pagination: Optional[str] = None
|
|
573
|
+
custom_instructions_for_data_extraction_from_page: Optional[str] = None
|
|
574
|
+
custom_instruction_to_fetch_details_page: Optional[str] = None
|
|
575
|
+
|
|
576
|
+
class SmartListSource(BaseModel):
|
|
577
|
+
"""
|
|
578
|
+
A single lead source definition. Contains the
|
|
579
|
+
source type (e.g., 'SALES_NAVIGATOR') plus the
|
|
580
|
+
relevant configuration.
|
|
581
|
+
"""
|
|
582
|
+
source_type: SmartListSourceType
|
|
583
|
+
input_type: SmartListInputType
|
|
584
|
+
configuration: SourceConfiguration
|
|
585
|
+
|
|
586
|
+
class SmartList(BaseModel):
|
|
587
|
+
id: Optional[UUID] = None
|
|
588
|
+
name: Optional[str] = None
|
|
589
|
+
description: Optional[str] = None
|
|
590
|
+
category: Optional[str] = None
|
|
591
|
+
status: SmartListStatus = SmartListStatus.DRAFT
|
|
592
|
+
start_date: Optional[int] = None
|
|
593
|
+
end_date: Optional[int] = None
|
|
594
|
+
|
|
595
|
+
sources: Optional[List[SmartListSource]] = None
|
|
596
|
+
|
|
597
|
+
qualification_instructions: Optional[str] = None
|
|
598
|
+
fetch_instructions: Optional[str] = None
|
|
599
|
+
max_items_to_search: Optional[int] = None
|
|
600
|
+
max_items_in_qualified_results: Optional[int] = None
|
|
601
|
+
enrich_information_from_online_research: bool = False
|
|
602
|
+
enrich_information_from_lead_website: bool = False
|
|
603
|
+
enrich_with_valid_email: bool = False
|
|
604
|
+
enrich_with_phone_number: bool = False
|
|
605
|
+
min_qualification_score: Optional[int] = None
|
|
606
|
+
number_of_leads_per_company: Optional[int] = None
|
|
607
|
+
|
|
608
|
+
agent_instance_id: Optional[UUID] = None
|
|
609
|
+
organization_id: Optional[UUID] = None
|
|
610
|
+
created_by: Optional[UUID] = None
|
|
611
|
+
created_at: Optional[int] = None
|
|
612
|
+
updated_by: Optional[UUID] = None
|
|
613
|
+
updated_at: Optional[int] = None
|
|
614
|
+
file_content: Optional[List[Any]] = None
|
|
615
|
+
account_qualification_instructions: Optional[str] = None
|
|
616
|
+
exclude_company_domains: Optional[List[Any]] = None
|
|
617
|
+
exclude_leads: Optional[List[Any]] = None
|
|
618
|
+
|
|
619
|
+
class Config:
|
|
620
|
+
from_attributes = True
|
|
621
|
+
|
|
622
|
+
class SmartListLead(BaseModel):
|
|
623
|
+
id: Optional[UUID] = None
|
|
624
|
+
|
|
625
|
+
smart_list_id: Optional[UUID] = None
|
|
626
|
+
|
|
627
|
+
full_name: Optional[str] = None
|
|
628
|
+
first_name: Optional[str] = None
|
|
629
|
+
last_name: Optional[str] = None
|
|
630
|
+
email: Optional[str] = None
|
|
631
|
+
user_linkedin_url: Optional[str] = None
|
|
632
|
+
user_linkedin_salesnav_url: Optional[str] = None
|
|
633
|
+
organization_linkedin_url: Optional[str] = None
|
|
634
|
+
organization_linkedin_salesnav_url: Optional[str] = None
|
|
635
|
+
primary_domain_of_organization: Optional[str] = None
|
|
636
|
+
twitter_handle: Optional[str] = None
|
|
637
|
+
github_handle: Optional[str] = None
|
|
638
|
+
job_title: Optional[str] = None
|
|
639
|
+
phone: Optional[str] = None
|
|
640
|
+
headline: Optional[str] = None
|
|
641
|
+
lead_location: Optional[str] = None
|
|
642
|
+
organization_name: Optional[str] = None
|
|
643
|
+
organization_website: Optional[str] = None
|
|
644
|
+
summary_about_lead: Optional[str] = None
|
|
645
|
+
keywords: Optional[Any] = None
|
|
646
|
+
additional_properties: Optional[Dict[str, Any]] = None
|
|
647
|
+
research_summary: Optional[str] = None
|
|
648
|
+
|
|
649
|
+
qualification_score: Optional[float] = None
|
|
650
|
+
qualification_reason: Optional[str] = None
|
|
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
|
|
657
|
+
|
|
658
|
+
agent_instance_id: Optional[UUID] = None
|
|
659
|
+
organization_id: Optional[UUID] = None
|
|
660
|
+
created_by: Optional[UUID] = None
|
|
661
|
+
created_at: Optional[int] = None
|
|
662
|
+
updated_by: Optional[UUID] = None
|
|
663
|
+
updated_at: Optional[int] = None
|
|
664
|
+
|
|
665
|
+
revenue: Optional[str] = None
|
|
666
|
+
company_size: Optional[str] = None
|
|
667
|
+
industry: Optional[str] = None
|
|
668
|
+
class Config:
|
|
669
|
+
from_attributes = True
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
class SmartListLog(BaseModel):
|
|
673
|
+
id: Optional[UUID] = None
|
|
674
|
+
message: str
|
|
675
|
+
|
|
676
|
+
smart_list_id: UUID
|
|
677
|
+
|
|
678
|
+
agent_instance_id: Optional[UUID] = None
|
|
679
|
+
organization_id: Optional[UUID] = None
|
|
680
|
+
created_by: Optional[UUID] = None
|
|
681
|
+
created_at: Optional[int] = None
|
|
682
|
+
updated_by: Optional[UUID] = None
|
|
683
|
+
updated_at: Optional[int] = None
|
|
684
|
+
|
|
685
|
+
class Config:
|
|
686
|
+
from_attributes = True
|
|
687
|
+
|
|
688
|
+
# --------------------------------------------------
|
|
689
|
+
# Updated LeadsQueryFilters
|
|
690
|
+
# --------------------------------------------------
|
|
691
|
+
class LeadsQueryFilters(BaseModel):
|
|
692
|
+
"""
|
|
693
|
+
Defines the filter parameters for querying leads in the Apollo database.
|
|
694
|
+
All fields are optional and default to None if not specified by user.
|
|
695
|
+
"""
|
|
696
|
+
|
|
697
|
+
# CHANGED: Renamed field to be more descriptive (person's current job titles)
|
|
698
|
+
person_current_titles: Optional[List[str]] = Field(
|
|
699
|
+
default=None,
|
|
700
|
+
description="List of job titles for the person (maps to Apollo's person_titles)."
|
|
701
|
+
)
|
|
702
|
+
|
|
703
|
+
# CHANGED: Renamed field to be more descriptive (person's locations)
|
|
704
|
+
person_locations: Optional[List[str]] = Field(
|
|
705
|
+
default=None,
|
|
706
|
+
description="List of personal locations (city, state, country). Maps to person_locations in Apollo."
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
# CHANGED: Renamed to be more descriptive
|
|
710
|
+
min_employees_in_organization: Optional[int] = Field(
|
|
711
|
+
default=None,
|
|
712
|
+
description="Minimum number of employees (>=1). Internally converted to a numeric range for Apollo."
|
|
713
|
+
)
|
|
714
|
+
max_employees_in_organization: Optional[int] = Field(
|
|
715
|
+
default=None,
|
|
716
|
+
description="Maximum number of employees (<=100000). Internally converted to a numeric range for Apollo."
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
filter_by_signals: Optional[List[str]] = Field(
|
|
720
|
+
default=None,
|
|
721
|
+
description="List of signals to filter by, e.g. ['RECENT_JOB_CHANGE']. Maps internally to search_signal_ids."
|
|
722
|
+
)
|
|
723
|
+
max_number_of_items_to_return: Optional[int] = Field(
|
|
724
|
+
default=None,
|
|
725
|
+
description="Max # of items (<=5000). Default=100."
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
# CHANGED: Renamed to be more descriptive
|
|
729
|
+
industries: Optional[List[str]] = Field(
|
|
730
|
+
default=None,
|
|
731
|
+
description="List of organization industries. Maps to organization_industries in Apollo."
|
|
732
|
+
)
|
|
733
|
+
|
|
734
|
+
# Potential existing fields
|
|
735
|
+
min_revenue_of_the_company: Optional[int] = Field(
|
|
736
|
+
default=None,
|
|
737
|
+
description="Minimum company revenue. Maps to revenueRange[min]."
|
|
738
|
+
)
|
|
739
|
+
max_revenue_of_the_company: Optional[int] = Field(
|
|
740
|
+
default=None,
|
|
741
|
+
description="Maximum company revenue. Maps to revenueRange[max]."
|
|
742
|
+
)
|
|
743
|
+
job_functions: Optional[List[str]] = Field(
|
|
744
|
+
default=None,
|
|
745
|
+
description="List of job functions (not directly used)."
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
# CHANGED: Renamed to be more descriptive
|
|
749
|
+
search_keywords: Optional[str] = Field(
|
|
750
|
+
default=None,
|
|
751
|
+
description="A string of keywords to filter results. Maps to q_keywords in Apollo."
|
|
752
|
+
)
|
|
753
|
+
|
|
754
|
+
# CHANGED: Renamed to be more descriptive
|
|
755
|
+
company_domains: Optional[List[str]] = Field(
|
|
756
|
+
default=None,
|
|
757
|
+
description="Domains of the person's employer (e.g., ['microsoft.com']). Maps to q_organization_domains."
|
|
758
|
+
)
|
|
759
|
+
|
|
760
|
+
# CHANGED: Renamed to be more descriptive
|
|
761
|
+
company_hq_locations: Optional[List[str]] = Field(
|
|
762
|
+
default=None,
|
|
763
|
+
description="List of HQ locations for the employer. Maps to organization_locations."
|
|
764
|
+
)
|
|
765
|
+
|
|
766
|
+
contact_email_status: Optional[List[str]] = Field(
|
|
767
|
+
default=None,
|
|
768
|
+
description="Email statuses, e.g. ['verified', 'unavailable']. Maps to contact_email_status."
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
# CHANGED: Renamed to be more descriptive
|
|
772
|
+
company_ids: Optional[List[str]] = Field(
|
|
773
|
+
default=None,
|
|
774
|
+
description="Apollo IDs for the companies (string IDs). Maps to organization_ids."
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
person_seniorities: Optional[List[str]] = Field(
|
|
778
|
+
default=None,
|
|
779
|
+
description=(
|
|
780
|
+
"List of job seniorities, e.g. ['manager', 'director', 'vp']. "
|
|
781
|
+
"Apollo supports: owner, founder, c_suite, partner, vp, head, "
|
|
782
|
+
"director, manager, senior, entry, intern."
|
|
783
|
+
)
|
|
784
|
+
)
|
|
785
|
+
|
|
786
|
+
# CHANGED: This replaces the old 'organization_job_titles' field
|
|
787
|
+
job_openings_with_titles: Optional[List[str]] = Field(
|
|
788
|
+
default=None,
|
|
789
|
+
description="List of job titles for posted positions in the organization. Maps to q_organization_job_titles."
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
# CHANGED: We no longer expose organization_num_employee_ranges to the user;
|
|
793
|
+
# we will build that internally from min_employees_in_organization & max_employees_in_organization.
|
|
794
|
+
|
|
795
|
+
latest_funding_stages: Optional[List[str]] = Field(
|
|
796
|
+
default=None,
|
|
797
|
+
description="List of funding stage codes, e.g. ['2', '3', '10']. Maps to organization_latest_funding_stage_cd."
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
# CHANGED: Renamed for consistency
|
|
801
|
+
company_industry_tag_ids: Optional[List[str]] = Field(
|
|
802
|
+
default=None,
|
|
803
|
+
description="List of industry tag IDs, e.g. ['5567cd4773696439b10b0000']. Maps to organization_industry_tag_ids."
|
|
804
|
+
)
|
|
805
|
+
|
|
806
|
+
q_organization_keyword_tags: Optional[List[str]] = Field(
|
|
807
|
+
default=None,
|
|
808
|
+
description="Organization Keyword tags to search by"
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
q_not_organization_keyword_tags: Optional[List[str]] = Field(
|
|
812
|
+
default=None,
|
|
813
|
+
description="Organization Keyword tags to search by"
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
q_organization_search_list_id: Optional[str] = Field(
|
|
817
|
+
default=None,
|
|
818
|
+
description="Include only organizations in a specific search list. Maps to qOrganizationSearchListId."
|
|
819
|
+
)
|
|
820
|
+
q_not_organization_search_list_id: Optional[str] = Field(
|
|
821
|
+
default=None,
|
|
822
|
+
description="Exclude organizations in a specific search list. Maps to qNotOrganizationSearchListId."
|
|
823
|
+
)
|
|
824
|
+
currently_using_any_of_technology_uids: Optional[List[str]] = Field(
|
|
825
|
+
default=None,
|
|
826
|
+
description="Technology UIDs used by the organization, e.g. ['google_font_api']."
|
|
827
|
+
)
|
|
828
|
+
sort_by_field: Optional[str] = Field(
|
|
829
|
+
default=None,
|
|
830
|
+
description="Sort field, e.g. '[none]', 'last_name', etc. Maps to sortByField."
|
|
831
|
+
)
|
|
832
|
+
sort_ascending: Optional[bool] = Field(
|
|
833
|
+
default=None,
|
|
834
|
+
description="Sort ascending or descending (maps to sortAscending)."
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
organization_num_employees_ranges: Optional[List[str]] = Field(
|
|
838
|
+
default=None,
|
|
839
|
+
description="Ranges for organization number of employees."
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
class CompanyQueryFilters(BaseModel):
|
|
844
|
+
"""
|
|
845
|
+
Defines the filter parameters for querying companies/organizations in the Apollo database.
|
|
846
|
+
All fields are optional and default to None if not specified by user.
|
|
847
|
+
"""
|
|
848
|
+
|
|
849
|
+
# Core company search parameters
|
|
850
|
+
organization_locations: Optional[List[str]] = Field(
|
|
851
|
+
default=None,
|
|
852
|
+
description="List of organization headquarters locations (city, state, country)."
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
organization_num_employees_ranges: Optional[List[str]] = Field(
|
|
856
|
+
default=None,
|
|
857
|
+
description="Employee count ranges, e.g. ['1,10', '11,50', '51,200']. Use specific ranges."
|
|
858
|
+
)
|
|
859
|
+
|
|
860
|
+
min_employees: Optional[int] = Field(
|
|
861
|
+
default=None,
|
|
862
|
+
description="Minimum number of employees (>=1). Internally converted to a numeric range."
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
max_employees: Optional[int] = Field(
|
|
866
|
+
default=None,
|
|
867
|
+
description="Maximum number of employees (<=100000). Internally converted to a numeric range."
|
|
868
|
+
)
|
|
869
|
+
|
|
870
|
+
organization_industries: Optional[List[str]] = Field(
|
|
871
|
+
default=None,
|
|
872
|
+
description="List of organization industries."
|
|
873
|
+
)
|
|
874
|
+
|
|
875
|
+
organization_industry_tag_ids: Optional[List[str]] = Field(
|
|
876
|
+
default=None,
|
|
877
|
+
description="List of industry tag IDs, e.g. ['5567cd4773696439b10b0000']."
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
q_organization_keyword_tags: Optional[List[str]] = Field(
|
|
881
|
+
default=None,
|
|
882
|
+
description="Organization Keyword tags to search by"
|
|
883
|
+
)
|
|
884
|
+
|
|
885
|
+
q_not_organization_keyword_tags: Optional[List[str]] = Field(
|
|
886
|
+
default=None,
|
|
887
|
+
description="Organization Keyword tags to search by"
|
|
888
|
+
)
|
|
889
|
+
|
|
890
|
+
# Revenue filters
|
|
891
|
+
revenue_range_min: Optional[int] = Field(
|
|
892
|
+
default=None,
|
|
893
|
+
description="Minimum company revenue in USD."
|
|
894
|
+
)
|
|
895
|
+
|
|
896
|
+
revenue_range_max: Optional[int] = Field(
|
|
897
|
+
default=None,
|
|
898
|
+
description="Maximum company revenue in USD."
|
|
899
|
+
)
|
|
900
|
+
|
|
901
|
+
# Funding and growth
|
|
902
|
+
organization_latest_funding_stage_cd: Optional[List[str]] = Field(
|
|
903
|
+
default=None,
|
|
904
|
+
description="List of funding stage codes, e.g. ['2', '3', '10']."
|
|
905
|
+
)
|
|
906
|
+
|
|
907
|
+
# Technology and keywords
|
|
908
|
+
currently_using_any_of_technology_uids: Optional[List[str]] = Field(
|
|
909
|
+
default=None,
|
|
910
|
+
description="Technology UIDs used by the organization, e.g. ['google_font_api']."
|
|
911
|
+
)
|
|
912
|
+
|
|
913
|
+
q_keywords: Optional[str] = Field(
|
|
914
|
+
default=None,
|
|
915
|
+
description="Keywords to search for in company descriptions, names, etc."
|
|
916
|
+
)
|
|
917
|
+
|
|
918
|
+
q_organization_domains: Optional[List[str]] = Field(
|
|
919
|
+
default=None,
|
|
920
|
+
description="Specific company domains to search for, e.g. ['microsoft.com', 'google.com']."
|
|
921
|
+
)
|
|
922
|
+
|
|
923
|
+
# Company-specific filters
|
|
924
|
+
organization_ids: Optional[List[str]] = Field(
|
|
925
|
+
default=None,
|
|
926
|
+
description="Specific Apollo organization IDs to include."
|
|
927
|
+
)
|
|
928
|
+
|
|
929
|
+
not_organization_ids: Optional[List[str]] = Field(
|
|
930
|
+
default=None,
|
|
931
|
+
description="Apollo organization IDs to exclude from results."
|
|
932
|
+
)
|
|
933
|
+
|
|
934
|
+
# Search lists
|
|
935
|
+
q_organization_search_list_id: Optional[str] = Field(
|
|
936
|
+
default=None,
|
|
937
|
+
description="Include only organizations in a specific search list."
|
|
938
|
+
)
|
|
939
|
+
|
|
940
|
+
q_not_organization_search_list_id: Optional[str] = Field(
|
|
941
|
+
default=None,
|
|
942
|
+
description="Exclude organizations in a specific search list."
|
|
943
|
+
)
|
|
944
|
+
|
|
945
|
+
# Sorting
|
|
946
|
+
sort_by_field: Optional[str] = Field(
|
|
947
|
+
default=None,
|
|
948
|
+
description="Sort field, e.g. 'name', 'employee_count', 'last_updated', etc."
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
sort_ascending: Optional[bool] = Field(
|
|
952
|
+
default=None,
|
|
953
|
+
description="Sort ascending (True) or descending (False)."
|
|
954
|
+
)
|
|
955
|
+
|
|
956
|
+
# Additional filters that might be useful
|
|
957
|
+
organization_founded_year_min: Optional[int] = Field(
|
|
958
|
+
default=None,
|
|
959
|
+
description="Minimum founding year for the organization."
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
organization_founded_year_max: Optional[int] = Field(
|
|
963
|
+
default=None,
|
|
964
|
+
description="Maximum founding year for the organization."
|
|
965
|
+
)
|