dhisana 0.0.1.dev17__tar.gz → 0.0.1.dev18__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/PKG-INFO +12 -2
  2. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/setup.py +4 -2
  3. dhisana-0.0.1.dev18/src/dhisana/schemas/common.py +370 -0
  4. dhisana-0.0.1.dev18/src/dhisana/schemas/sales.py +276 -0
  5. dhisana-0.0.1.dev18/src/dhisana/utils/agent_task.py +177 -0
  6. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/apollo_tools.py +172 -70
  7. dhisana-0.0.1.dev18/src/dhisana/utils/check_email_validity_tools.py +177 -0
  8. dhisana-0.0.1.dev18/src/dhisana/utils/check_for_intent_signal.py +56 -0
  9. dhisana-0.0.1.dev18/src/dhisana/utils/check_linkedin_url_validity.py +183 -0
  10. dhisana-0.0.1.dev18/src/dhisana/utils/compose_salesnav_query.py +157 -0
  11. dhisana-0.0.1.dev18/src/dhisana/utils/compose_workflow.py +239 -0
  12. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/dataframe_tools.py +1 -1
  13. dhisana-0.0.1.dev18/src/dhisana/utils/domain_parser.py +45 -0
  14. dhisana-0.0.1.dev18/src/dhisana/utils/enrich_lead_information.py +241 -0
  15. dhisana-0.0.1.dev18/src/dhisana/utils/generate_email.py +157 -0
  16. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/generate_email_response.py +2 -2
  17. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/generate_linkedin_connect_message.py +14 -2
  18. dhisana-0.0.1.dev18/src/dhisana/utils/generate_structured_output_internal.py +119 -0
  19. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/google_workspace_tools.py +6 -6
  20. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/hubspot_crm_tools.py +163 -27
  21. dhisana-0.0.1.dev18/src/dhisana/utils/lusha_tools.py +330 -0
  22. dhisana-0.0.1.dev18/src/dhisana/utils/openai_assistant_and_file_utils.py +1013 -0
  23. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/openai_helpers.py +0 -30
  24. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/proxy_curl_tools.py +247 -8
  25. dhisana-0.0.1.dev18/src/dhisana/utils/research_lead.py +118 -0
  26. dhisana-0.0.1.dev18/src/dhisana/utils/sales_navigator_crawler.py +1108 -0
  27. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/serpapi_search_tools.py +25 -13
  28. dhisana-0.0.1.dev18/src/dhisana/utils/zoominfo_tools.py +358 -0
  29. dhisana-0.0.1.dev18/src/dhisana/workflow/__init__.py +1 -0
  30. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana.egg-info/PKG-INFO +12 -2
  31. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana.egg-info/SOURCES.txt +10 -0
  32. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana.egg-info/requires.txt +2 -0
  33. dhisana-0.0.1.dev17/src/dhisana/utils/check_email_validity_tools.py +0 -73
  34. dhisana-0.0.1.dev17/src/dhisana/utils/check_linkedin_url_validity.py +0 -63
  35. dhisana-0.0.1.dev17/src/dhisana/utils/enrich_lead_information.py +0 -303
  36. dhisana-0.0.1.dev17/src/dhisana/utils/generate_email.py +0 -56
  37. dhisana-0.0.1.dev17/src/dhisana/utils/lusha_tools.py +0 -306
  38. dhisana-0.0.1.dev17/src/dhisana/utils/research_lead.py +0 -52
  39. dhisana-0.0.1.dev17/src/dhisana/utils/sales_navigator_crawler.py +0 -382
  40. dhisana-0.0.1.dev17/src/dhisana/utils/zoominfo_tools.py +0 -550
  41. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/README.md +0 -0
  42. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/pyproject.toml +0 -0
  43. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/setup.cfg +0 -0
  44. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/__init__.py +0 -0
  45. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/cli/__init__.py +0 -0
  46. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/cli/cli.py +0 -0
  47. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/cli/datasets.py +0 -0
  48. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/cli/models.py +0 -0
  49. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/cli/predictions.py +0 -0
  50. {dhisana-0.0.1.dev17/src/dhisana/ui → dhisana-0.0.1.dev18/src/dhisana/schemas}/__init__.py +0 -0
  51. {dhisana-0.0.1.dev17/src/dhisana/utils → dhisana-0.0.1.dev18/src/dhisana/ui}/__init__.py +0 -0
  52. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/ui/components.py +0 -0
  53. {dhisana-0.0.1.dev17/src/dhisana/utils/openapi_tool → dhisana-0.0.1.dev18/src/dhisana/utils}/__init__.py +0 -0
  54. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/agent_tools.py +0 -0
  55. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/assistant_tool_tag.py +0 -0
  56. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/built_with_api_tools.py +0 -0
  57. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/cache_output_tools.py +0 -0
  58. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/clay_tools.py +0 -0
  59. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/company_utils.py +0 -0
  60. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/composite_tools.py +0 -0
  61. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/g2_tools.py +0 -0
  62. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/generate_flow.py +0 -0
  63. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/google_custom_search.py +0 -0
  64. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/hubspot_clearbit.py +0 -0
  65. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/instantly_tools.py +0 -0
  66. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/linkedin_crawler.py +0 -0
  67. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
  68. {dhisana-0.0.1.dev17/src/dhisana/workflow → dhisana-0.0.1.dev18/src/dhisana/utils/openapi_tool}/__init__.py +0 -0
  69. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
  70. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
  71. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
  72. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/python_function_to_tools.py +0 -0
  73. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
  74. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/sendgrid_tools.py +0 -0
  75. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/trasform_json.py +0 -0
  76. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/utils/web_download_parse_tools.py +0 -0
  77. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/workflow/agent.py +0 -0
  78. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/workflow/flow.py +0 -0
  79. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/workflow/task.py +0 -0
  80. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana/workflow/test.py +0 -0
  81. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana.egg-info/dependency_links.txt +0 -0
  82. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana.egg-info/entry_points.txt +0 -0
  83. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/src/dhisana.egg-info/top_level.txt +0 -0
  84. {dhisana-0.0.1.dev17 → dhisana-0.0.1.dev18}/tests/test_agent_tools.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dhisana
3
- Version: 0.0.1.dev17
3
+ Version: 0.0.1.dev18
4
4
  Summary: A Python SDK for Dhisana AI Platform
5
5
  Home-page: https://github.com/dhisana-ai/dhisana-python-sdk
6
6
  Author: Admin
@@ -27,3 +27,13 @@ Requires-Dist: simple_salesforce
27
27
  Requires-Dist: backoff
28
28
  Requires-Dist: html2text
29
29
  Requires-Dist: hubspot-api-client
30
+ Requires-Dist: tldextract
31
+ Requires-Dist: pyperclip
32
+ Dynamic: author
33
+ Dynamic: author-email
34
+ Dynamic: classifier
35
+ Dynamic: home-page
36
+ Dynamic: license
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='dhisana',
5
- version='0.0.1-dev17',
5
+ version='0.0.1-dev18',
6
6
  description='A Python SDK for Dhisana AI Platform',
7
7
  author='Admin',
8
8
  author_email='contact@dhisana.ai',
@@ -26,7 +26,9 @@ setup(
26
26
  'simple_salesforce',
27
27
  'backoff',
28
28
  'html2text',
29
- 'hubspot-api-client'
29
+ 'hubspot-api-client',
30
+ 'tldextract',
31
+ 'pyperclip'
30
32
  ],
31
33
  entry_points={
32
34
  'console_scripts': [
@@ -0,0 +1,370 @@
1
+ from uuid import UUID
2
+ from pydantic import BaseModel, Field, HttpUrl
3
+ from typing import List, Optional, Dict, Any
4
+ from enum import Enum
5
+
6
+ ##
7
+ # PERMISSION & ROLE
8
+ ##
9
+
10
+ class PermissionBase(BaseModel):
11
+ name: str
12
+ description: Optional[str] = None
13
+
14
+ class PermissionCreate(PermissionBase):
15
+ pass
16
+
17
+ class Permission(PermissionBase):
18
+ id: int
19
+
20
+ class Config:
21
+ from_attributes = True
22
+
23
+ class RoleBase(BaseModel):
24
+ name: str
25
+ description: Optional[str] = None
26
+
27
+ class RoleCreate(RoleBase):
28
+ permission_ids: List[int] = []
29
+
30
+ class Role(RoleBase):
31
+ id: int
32
+ permissions: List[Permission] = []
33
+
34
+ class Config:
35
+ from_attributes = True
36
+
37
+
38
+ ##
39
+ # ORGANIZATION
40
+ ##
41
+
42
+ class OrganizationBase(BaseModel):
43
+ name: str
44
+ description: Optional[str] = None
45
+
46
+ class OrganizationCreate(OrganizationBase):
47
+ pass
48
+
49
+ class Organization(OrganizationBase):
50
+ id: UUID
51
+ # changed from datetime -> milliseconds since epoch
52
+ created_at: Optional[int] = None
53
+
54
+ class Config:
55
+ from_attributes = True
56
+
57
+
58
+ ##
59
+ # USER
60
+ ##
61
+
62
+ class UserBase(BaseModel):
63
+ id: str
64
+ username: Optional[str]
65
+ email: Optional[str]
66
+ organization_id: Optional[UUID]
67
+ created_at: Optional[int] = None
68
+
69
+ class UserCreate(UserBase):
70
+ pass
71
+
72
+ class User(UserBase):
73
+ roles: List[Role] = []
74
+
75
+ class Config:
76
+ from_attributes = True
77
+
78
+
79
+ ##
80
+ # AGENT + STATUSES
81
+ ##
82
+
83
+ class AgentStatus(str, Enum):
84
+ PENDING = "PENDING"
85
+ APPROVED = "APPROVED"
86
+ REJECTED = "REJECTED"
87
+ PUBLISHED = "PUBLISHED"
88
+
89
+ class AgentStatusUpdate(BaseModel):
90
+ status: AgentStatus
91
+
92
+ class AgentInstanceStatus(str, Enum):
93
+ ACTIVE = "ACTIVE"
94
+ INACTIVE = "INACTIVE"
95
+ ERROR = "ERROR"
96
+
97
+
98
+ ##
99
+ # UI / CONFIG FIELDS
100
+ ##
101
+
102
+ class SelectOption(BaseModel):
103
+ label: str
104
+ value: Any
105
+
106
+ class ValidationRules(BaseModel):
107
+ required: Optional[bool] = None
108
+ min: Optional[int] = None
109
+ max: Optional[int] = None
110
+ pattern: Optional[str] = None
111
+
112
+ class ConfigField(BaseModel):
113
+ name: str
114
+ label: str
115
+ type: str
116
+ sensitive: Optional[bool] = False
117
+ default: Optional[Any] = Field(None, alias="default")
118
+ description: Optional[str] = None
119
+ validations: Optional[ValidationRules] = None
120
+ options: Optional[List[SelectOption]] = None
121
+ fields: Optional[List["ConfigField"]] = None # for nested structures
122
+
123
+ class Config:
124
+ populate_by_name = True
125
+
126
+ ConfigField.model_rebuild()
127
+
128
+ class ConfigGroup(BaseModel):
129
+ groupName: str
130
+ fields: List[ConfigField]
131
+
132
+ class BackendDefinition(BaseModel):
133
+ docker_image: Optional[str] = None
134
+ environment_variables: Optional[Dict[str, str]] = None
135
+ container_id: Optional[str] = None
136
+
137
+ class LayoutType(str, Enum):
138
+ SINGLE_COLUMN = "single-column"
139
+ TWO_COLUMN = "two-column"
140
+ DASHBOARD = "dashboard"
141
+ CHAT_INTERFACE = "chat-interface"
142
+ SMART_LIST_BUILDER = "smart-list-builder"
143
+
144
+ class ComponentType(str, Enum):
145
+ CHAT_WINDOW = "chat-window"
146
+ HEADER = "header"
147
+ FOOTER = "footer"
148
+ SIDEBAR = "sidebar"
149
+ MAIN_CONTENT = "main-content"
150
+ DATA_TABLE = "data-table"
151
+ CHART = "chart"
152
+ FORM = "form"
153
+ BUTTON = "button"
154
+ TEXT = "text"
155
+ IMAGE = "image"
156
+ VIDEO = "video"
157
+ CUSTOM_COMPONENT = "custom-component"
158
+ TABS = "tabs"
159
+ TAB = "tab"
160
+ FORM_ITEM = "form-item"
161
+ INPUT = "input"
162
+ TEXTAREA = "textarea"
163
+ UPLOAD = "upload"
164
+
165
+ class ComponentPosition(BaseModel):
166
+ row: Optional[int] = None
167
+ column: Optional[int] = None
168
+ area: Optional[str] = None
169
+
170
+ class RenderComponent(BaseModel):
171
+ type: ComponentType
172
+ position: Optional[ComponentPosition] = None
173
+ properties: Optional[Dict[str, Any]] = None
174
+ children: Optional[List["RenderComponent"]] = None
175
+ injector: Optional[Any] = None
176
+
177
+ class ActionDefinition(BaseModel):
178
+ type: str
179
+ method: str
180
+ url: str
181
+ data: Optional[Any] = None
182
+ state: Optional[str] = None
183
+ onSuccess: Optional[str] = None
184
+
185
+ class RenderDefinition(BaseModel):
186
+ layout: LayoutType
187
+ components: List[RenderComponent]
188
+ actions: Optional[Dict[str, ActionDefinition]] = None
189
+ initialActions: Optional[List[str]] = None
190
+
191
+ class ConfigValue(BaseModel):
192
+ name: str
193
+ value: Any
194
+ fields: Optional[List["ConfigValue"]] = None
195
+
196
+ class Config:
197
+ populate_by_name = True
198
+
199
+ ConfigValue.model_rebuild()
200
+
201
+ class SchemaDefinition(BaseModel):
202
+ name: str
203
+ version: str
204
+ fields: List[ConfigField]
205
+ migrations: Optional[List[Dict[str, Any]]] = None
206
+
207
+ ##
208
+ # AGENT
209
+ ##
210
+
211
+ class Agent(BaseModel):
212
+ id: Optional[UUID] = None
213
+ name: str
214
+ description: str
215
+ image_url: str
216
+ expertise: List[str]
217
+ version: str
218
+ schema_definition: Optional[List[SchemaDefinition]] = None
219
+ config_definition: List[ConfigGroup]
220
+ agent_config_definition: Optional[List[ConfigGroup]] = None
221
+ agent_configuration: Optional[List[ConfigValue]] = None
222
+ render_definition: RenderDefinition
223
+ backend: BackendDefinition
224
+ repository_url: Optional[str] = None
225
+ status: Optional[AgentStatus] = AgentStatus.PENDING
226
+
227
+ organization_id: Optional[UUID] = None
228
+ created_by: Optional[str] = None
229
+
230
+ # changed from datetime -> milliseconds since epoch
231
+ created_at: Optional[int] = None
232
+
233
+ updated_by: Optional[str] = None
234
+ updated_at: Optional[int] = None
235
+
236
+ class Config:
237
+ from_attributes = True
238
+ populate_by_name = True
239
+
240
+ ##
241
+ # AGENT INSTANCE
242
+ ##
243
+
244
+ class AgentInstance(BaseModel):
245
+ id: Optional[UUID] = None
246
+ published_agent_id: UUID
247
+ name: str
248
+ description: str
249
+ image_url: str
250
+ expertise: Optional[List[str]] = None
251
+ version: str
252
+ schema_definition: Optional[List[SchemaDefinition]] = None
253
+ configuration: List[ConfigValue]
254
+ render_definition: RenderDefinition = None
255
+ backend: BackendDefinition = None
256
+ status: AgentInstanceStatus = AgentInstanceStatus.INACTIVE
257
+ status_message: Optional[str] = None
258
+ service_url: Optional[str] = None
259
+ port: Optional[int] = None
260
+
261
+ organization_id: Optional[UUID] = None
262
+ created_by: Optional[str] = None
263
+ # changed from datetime -> milliseconds
264
+ created_at: Optional[int] = None
265
+ updated_by: Optional[str] = None
266
+ updated_at: Optional[int] = None
267
+
268
+ class Config:
269
+ from_attributes = True
270
+ populate_by_name = True
271
+
272
+
273
+ ##
274
+ # AGENT INSTANCE DATA
275
+ ##
276
+
277
+ class AgentInstanceData(BaseModel):
278
+ id: Optional[UUID] = None
279
+ type: str
280
+ version: str
281
+ agent_instance_id: UUID
282
+ organization_id: UUID
283
+ data: Dict[str, Any]
284
+ # changed from datetime -> milliseconds
285
+ created_at: Optional[int] = None
286
+ updated_at: Optional[int] = None
287
+
288
+ class Config:
289
+ populate_by_name = True
290
+
291
+
292
+ ##
293
+ # SOURCE
294
+ ##
295
+
296
+ class SourceType(str, Enum):
297
+ FILE = "file"
298
+ GOOGLE_DOC = "google_doc"
299
+ WEBSITE = "website"
300
+ YOUTUBE = "youtube"
301
+ TEXT = "text"
302
+
303
+ class SourceBase(BaseModel):
304
+ source_type: SourceType
305
+ title: Optional[str] = None
306
+ source_metadata: Optional[dict] = None
307
+ blob_url: Optional[HttpUrl] = None
308
+ content: Optional[str] = None
309
+
310
+ class SourceCreate(SourceBase):
311
+ pass
312
+
313
+ class SourceUpdate(SourceBase):
314
+ pass
315
+
316
+ class Source(SourceBase):
317
+ id: UUID
318
+ agent_instance_id: UUID
319
+ # changed from datetime -> milliseconds
320
+ created_at: Optional[int] = None
321
+
322
+ class Config:
323
+ populate_by_name = True
324
+
325
+ ##
326
+ # INTEGRATION
327
+ ##
328
+
329
+ class IntegrationStatus(str, Enum):
330
+ CONNECTED = "connected"
331
+ DISCONNECTED = "disconnected"
332
+ COMING_SOON = "coming soon"
333
+
334
+ class IntegrationBase(BaseModel):
335
+ name: str
336
+ label: str
337
+ icon: Optional[str] = None
338
+ description: Optional[str] = None
339
+ category: Optional[str] = None
340
+ tags: Optional[List[str]] = None
341
+ status: IntegrationStatus = IntegrationStatus.DISCONNECTED
342
+ configuration: Optional[List["ConfigValue"]] = None
343
+
344
+ class IntegrationCreate(IntegrationBase):
345
+ agent_instance_id: UUID
346
+ organization_id: UUID
347
+
348
+ class IntegrationUpdate(BaseModel):
349
+ name: Optional[str] = None
350
+ label: Optional[str] = None
351
+ icon: Optional[str] = None
352
+ description: Optional[str] = None
353
+ category: Optional[str] = None
354
+ tags: Optional[List[str]] = None
355
+ status: Optional[IntegrationStatus] = None
356
+ configuration: Optional[List["ConfigValue"]] = None
357
+
358
+ class Integration(IntegrationBase):
359
+ id: UUID
360
+ agent_instance_id: UUID
361
+ organization_id: UUID
362
+ # changed from datetime -> milliseconds
363
+ created_at: Optional[int] = None
364
+
365
+ class Config:
366
+ from_attributes = True
367
+ populate_by_name = True
368
+
369
+ Integration.model_rebuild()
370
+ IntegrationUpdate.model_rebuild()
@@ -0,0 +1,276 @@
1
+ from uuid import UUID
2
+ from pydantic import BaseModel, Field
3
+ from typing import List, Optional, Dict, Any
4
+ from enum import Enum
5
+ from typing import Optional, List, Dict, Literal
6
+
7
+ from dhisana.schemas.common import User
8
+
9
+ # -----------------------------
10
+ # Lead-List-Specific Schemas
11
+ # -----------------------------
12
+
13
+ class Lead(BaseModel):
14
+ id: Optional[str] = None
15
+ full_name: Optional[str] = None
16
+ first_name: Optional[str] = None
17
+ last_name: Optional[str] = None
18
+ email: Optional[str] = None
19
+ user_linkedin_url: Optional[str] = None
20
+ primary_domain_of_organization: Optional[str] = None
21
+ job_title: Optional[str] = None
22
+ phone: Optional[str] = None
23
+ headline: Optional[str] = None
24
+ lead_location: Optional[str] = None
25
+ organization_name: Optional[str] = None
26
+ organization_website: Optional[str] = None
27
+ summary_about_lead: Optional[str] = None
28
+ keywords: Optional[List[str]] = None
29
+ workflow_stage: Optional[str] = None
30
+ assigned_to: Optional[str] = None
31
+ engaged: Optional[bool] = None
32
+ last_contact: Optional[int] = None
33
+ additional_properties: Optional[Dict[str, str]] = None
34
+ research_summary: Optional[str] = None
35
+ task_ids: Optional[List[str]] = None
36
+ email_validation_status: Optional[
37
+ Literal["not_started", "in_progress", "valid", "invalid"]
38
+ ] = None
39
+ linkedin_validation_status: Optional[
40
+ Literal["not_started", "in_progress", "valid", "invalid"]
41
+ ] = None
42
+ research_status: Optional[
43
+ Literal["not_started", "in_progress", "done", "failed"]
44
+ ] = None
45
+ enchrichment_status: Optional[
46
+ Literal["not_started", "in_progress", "done", "failed"]
47
+ ] = None
48
+
49
+
50
+ class LeadList(BaseModel):
51
+ id: Optional[str] = None
52
+ name: str
53
+ sources: List[str]
54
+ tags: List[str]
55
+ category: str
56
+ leads_count: int
57
+ assigned_users: List[str]
58
+ updated_at: int
59
+ status: Literal["connected", "disconnected", "coming soon"]
60
+ leads: Optional[List[Lead]] = None
61
+ public: Optional[bool] = None
62
+
63
+ # -----------------------------
64
+ # Task-Specific Schemas
65
+ # -----------------------------
66
+
67
+ class TaskStatus(str, Enum):
68
+ PENDING = "PENDING"
69
+ RUNNING = "RUNNING"
70
+ FAILED = "FAILED"
71
+ COMPLETED = "COMPLETED"
72
+
73
+ class TaskBase(BaseModel):
74
+ name: str
75
+ task_type: str
76
+ data_id: Optional[UUID] = None
77
+ data_type: Optional[str] = None
78
+
79
+ inputs: Optional[List[Dict[str, Any]]] = []
80
+ outputs: Optional[List[Dict[str, Any]]] = []
81
+
82
+ class TaskCreate(TaskBase):
83
+ pass
84
+
85
+ class TaskUpdate(BaseModel):
86
+ status: Optional[TaskStatus] = None
87
+ logs: Optional[List[Any]] = None
88
+ metrics: Optional[Dict[str, Any]] = None
89
+ outputs: Optional[List[Dict[str, Any]]] = None
90
+
91
+ class Task(TaskBase):
92
+ id: UUID
93
+ status: TaskStatus
94
+ logs: List[Any] = []
95
+ metrics: Dict[str, Any] = {}
96
+ created_at: int # store as ms since epoch
97
+ updated_at: int
98
+ completed_at: Optional[int] = None
99
+
100
+ class Config:
101
+ from_attributes = True
102
+
103
+
104
+ # -----------------------------
105
+ # Campaign-Specific Schemas
106
+ # -----------------------------
107
+
108
+ class SendRules(BaseModel):
109
+ daily_send_limit: Optional[int] = None
110
+ concurrency_limit: Optional[int] = None
111
+ time_window_start: Optional[str] = None # "HH:MM" string
112
+ time_window_end: Optional[str] = None
113
+ block_weekends: Optional[bool] = False
114
+
115
+ class Touch(BaseModel):
116
+ type: str # e.g. 'email', 'linkedin', ...
117
+ action: str # e.g. 'view_linked_in_profile', 'send_connection_request'
118
+ details: str
119
+ delay_days: int
120
+ template_id: Optional[str] = None
121
+
122
+ class PromptEngineeringGuidance(BaseModel):
123
+ tone: str
124
+ word_count: int
125
+ paragraphs: int
126
+
127
+ class LeadLog(BaseModel):
128
+ id: Optional[str] = None
129
+ message: str
130
+ channel: Optional[str] = None
131
+ timestamp: int # ms since epoch
132
+ status: Optional[str] = None
133
+
134
+ class CampaignLead(BaseModel):
135
+ id: Optional[str] = None
136
+ campaign_id: str
137
+ lead_list_id: Optional[str] = None
138
+ lead_id: Optional[str] = None
139
+ lead_name: str
140
+
141
+ status: Optional[str] = None # 'PENDING', 'WAITING_APPROVAL', 'OUTBOUND_PENDING', 'COMPLETED'
142
+ current_step: Optional[int] = 0
143
+ total_steps: Optional[int] = 0
144
+ engaged: Optional[bool] = False
145
+ last_touch: Optional[str] = None
146
+ created_at: Optional[int] = None # ms since epoch
147
+ updated_at: Optional[int] = None
148
+
149
+ logs: Optional[List[LeadLog]] = None
150
+
151
+ class CampaignCounter(BaseModel):
152
+ id: Optional[str] = None
153
+ campaign_id: str
154
+ date: str # "YYYY-MM-DD"
155
+ daily_sends: int
156
+ current_concurrency: int
157
+
158
+ class CampaignStatus(str, Enum):
159
+ DRAFT = "DRAFT"
160
+ ACTIVE = "ACTIVE"
161
+ PAUSED = "PAUSED"
162
+ COMPLETED = "COMPLETED"
163
+
164
+ class PendingEvent(BaseModel):
165
+ event_id: str
166
+ lead_id: str
167
+ touch_index: int
168
+ channel: str
169
+ action: str
170
+ subject: str
171
+ message: str
172
+ created_at: int # ms since epoch
173
+
174
+ class Campaign(BaseModel):
175
+ id: str
176
+ name: str
177
+ description: str
178
+ lead_lists: List[str]
179
+ run_mode: str
180
+ updated_at: int # ms since epoch
181
+
182
+ tags: Optional[List[str]] = None
183
+ channel: Optional[str] = None
184
+ mission_objective: Optional[str] = None
185
+ mission_progress: Optional[int] = None
186
+ ai_alerts: Optional[List[str]] = None
187
+ automatic_adjustments: Optional[List[str]] = None
188
+
189
+ product_name: Optional[str] = None
190
+ value_prop: Optional[str] = None
191
+ call_to_action: Optional[str] = None
192
+ pain_points: Optional[List[str]] = None
193
+ proof_points: Optional[List[str]] = None
194
+ prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
195
+ prompt_templates: Optional[List[Dict[str, Any]]] = None
196
+ touches: Optional[List[Touch]] = None
197
+ send_rules: Optional[SendRules] = None
198
+
199
+ status: Optional[CampaignStatus] = None
200
+ start_date: Optional[int] = None # ms since epoch
201
+ pause_date: Optional[int] = None
202
+ end_date: Optional[int] = None
203
+
204
+ leads: Optional[List[CampaignLead]] = None
205
+ counter: Optional[CampaignCounter] = None
206
+ pending_events: Optional[List[PendingEvent]] = None
207
+
208
+ class Config:
209
+ from_attributes = True
210
+
211
+ class EmailContentContext(BaseModel):
212
+ product_name: Optional[str] = None
213
+ value_prop: Optional[str] = None
214
+ call_to_action: Optional[str] = None
215
+ pain_points: Optional[List[str]] = None
216
+ proof_points: Optional[List[str]] = None
217
+ prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
218
+
219
+ lead_info: Lead
220
+
221
+ sender_full_name: str
222
+ sender_first_name: str
223
+ sender_last_name: str
224
+
225
+ email_subject_template: str
226
+ email_body_template: str
227
+ external_source_fileIds: Dict[str, Any]
228
+ external_openai_vector_store_id: Optional[str]
229
+ additional_instructions: str
230
+
231
+ # --------------------------------------------------------------------
232
+ # 1. Define your HubSpotLeadInformation model
233
+ # --------------------------------------------------------------------
234
+ class HubSpotLeadInformation(BaseModel):
235
+ full_name: str = Field("", description="Full name of the lead")
236
+ first_name: str = Field("", description="First name of the lead")
237
+ last_name: str = Field("", description="Last name of the lead")
238
+ email: str = Field("", description="Email address of the lead")
239
+ user_linkedin_url: str = Field("", description="LinkedIn URL of the lead")
240
+ primary_domain_of_organization: str = Field("", description="Primary domain of the organization")
241
+ job_title: str = Field("", description="Job Title of the lead")
242
+ phone: str = Field("", description="Phone number of the lead")
243
+ headline: str = Field("", description="Headline of the lead")
244
+ lead_location: str = Field("", description="Location of the lead")
245
+ organization_name: str = Field("", description="Current Company where lead works")
246
+ organization_website: str = Field("", description="Current Company website of the lead")
247
+ # additional_properties is dict of dict-of-strings.
248
+ # We store all unmapped HubSpot fields as string => string.
249
+ additional_properties: Dict[str, Dict[str, str]] = Field(
250
+ default_factory=lambda: {"hubspot_lead_information": {}},
251
+ description="Store all extra HubSpot fields not mapped to standard ones"
252
+ )
253
+
254
+ # --------------------------------------------------------------------
255
+ # 2. Map HubSpot property names -> HubSpotLeadInformation fields
256
+ # --------------------------------------------------------------------
257
+ HUBSPOT_TO_LEAD_MAPPING = {
258
+ "firstname": "first_name",
259
+ "lastname": "last_name",
260
+ "email": "email",
261
+ "phone": "phone",
262
+ "jobtitle": "job_title", # Default HubSpot job title property
263
+ "company": "organization_name", # Map "company" -> "organization_name"
264
+ "website": "organization_website", # Map "website" -> "organization_website"
265
+ "address": "lead_location", # You can choose "city", "state", etc. if you prefer
266
+ "city": "lead_location",
267
+ "domain": "primary_domain_of_organization",
268
+ }
269
+
270
+ # Potential LinkedIn fallback properties from hubspot.
271
+ LINKEDIN_FALLBACK_FIELDS = [
272
+ "person_profile_url",
273
+ "user_linkedin_url",
274
+ "lead_linkedin_url",
275
+ "contact_linkedin_url",
276
+ ]