dhisana 0.0.1.dev101__tar.gz → 0.0.1.dev103__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.dev101 → dhisana-0.0.1.dev103}/PKG-INFO +1 -1
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/setup.py +1 -1
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/apollo_tools.py +11 -1
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/check_email_validity_tools.py +17 -1
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/enrich_lead_information.py +3 -3
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_email.py +1 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_email_response.py +4 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_linkedin_connect_message.py +4 -4
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_linkedin_response_message.py +19 -4
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openai_assistant_and_file_utils.py +3 -3
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/research_lead.py +33 -8
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/test_connect.py +1 -1
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana.egg-info/PKG-INFO +1 -1
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/README.md +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/pyproject.toml +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/setup.cfg +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/__init__.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/cli/__init__.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/cli/cli.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/cli/datasets.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/cli/models.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/cli/predictions.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/schemas/__init__.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/schemas/common.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/schemas/sales.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/ui/__init__.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/ui/components.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/__init__.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/add_mapping.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/agent_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/assistant_tool_tag.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/built_with_api_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/cache_output_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/cache_output_tools_local.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/check_for_intent_signal.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/check_linkedin_url_validity.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/clay_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/clean_properties.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/company_utils.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/compose_salesnav_query.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/compose_search_query.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/composite_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/dataframe_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/domain_parser.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/email_parse_helpers.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/field_validators.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/g2_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_content.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_flow.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_structured_output_internal.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/google_custom_search.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/google_workspace_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/hubspot_clearbit.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/hubspot_crm_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/instantly_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/linkedin_crawler.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/lusha_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openai_helpers.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/proxy_curl_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/python_function_to_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/sendgrid_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/serpapi_search_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/trasform_json.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/web_download_parse_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/workflow_code_model.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/zoominfo_tools.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/workflow/__init__.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/workflow/agent.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/workflow/flow.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/workflow/task.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/workflow/test.py +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana.egg-info/SOURCES.txt +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana.egg-info/dependency_links.txt +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana.egg-info/entry_points.txt +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana.egg-info/requires.txt +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana.egg-info/top_level.txt +0 -0
- {dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/tests/test_agent_tools.py +0 -0
|
@@ -192,6 +192,16 @@ async def lookup_person_in_apollo_by_name(
|
|
|
192
192
|
"per_page": 10
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
# Build a cache key that includes full_name and company_name (if provided)
|
|
196
|
+
# so that results are correctly cached and retrieved.
|
|
197
|
+
key_item = f"lookup_person_in_apollo_by_name_{full_name}_{company_name or ''}".lower()
|
|
198
|
+
|
|
199
|
+
# Attempt to retrieve a cached response first
|
|
200
|
+
cached_response = retrieve_output("lookup_person_in_apollo_by_name", key_item)
|
|
201
|
+
if cached_response is not None:
|
|
202
|
+
logger.info(f"Cache hit for user: {full_name}, company: {company_name or ''}")
|
|
203
|
+
return cached_response
|
|
204
|
+
|
|
195
205
|
url = 'https://api.apollo.io/api/v1/mixed_people/search'
|
|
196
206
|
logger.debug(f"Making request to Apollo with payload: {data}")
|
|
197
207
|
|
|
@@ -202,6 +212,7 @@ async def lookup_person_in_apollo_by_name(
|
|
|
202
212
|
if response.status == 200:
|
|
203
213
|
result = await response.json()
|
|
204
214
|
logger.info("Successfully looked up person by name on Apollo.")
|
|
215
|
+
cache_output("lookup_person_in_apollo_by_name", key_item, result)
|
|
205
216
|
return result
|
|
206
217
|
elif response.status == 429:
|
|
207
218
|
msg = "Rate limit exceeded"
|
|
@@ -222,7 +233,6 @@ async def lookup_person_in_apollo_by_name(
|
|
|
222
233
|
logger.exception("Exception occurred while looking up person by name.")
|
|
223
234
|
return {'error': str(e)}
|
|
224
235
|
|
|
225
|
-
|
|
226
236
|
@assistant_tool
|
|
227
237
|
@backoff.on_exception(
|
|
228
238
|
backoff.expo,
|
{dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/check_email_validity_tools.py
RENAMED
|
@@ -220,6 +220,18 @@ async def check_email_validity_with_hunter(
|
|
|
220
220
|
"confidence": "low",
|
|
221
221
|
"is_valid": False
|
|
222
222
|
}
|
|
223
|
+
|
|
224
|
+
cache_key = f"{email_id}"
|
|
225
|
+
cached_response = retrieve_output("hunter_validate", cache_key)
|
|
226
|
+
if cached_response is not None:
|
|
227
|
+
logger.info("Cache hit for Hunter validate.")
|
|
228
|
+
if not cached_response:
|
|
229
|
+
return {
|
|
230
|
+
"email": email_id,
|
|
231
|
+
"confidence": "low",
|
|
232
|
+
"is_valid": False
|
|
233
|
+
}
|
|
234
|
+
return json.loads(cached_response[0])
|
|
223
235
|
|
|
224
236
|
HUNTER_API_KEY = get_hunter_access_token(tool_config)
|
|
225
237
|
if not HUNTER_API_KEY:
|
|
@@ -241,11 +253,14 @@ async def check_email_validity_with_hunter(
|
|
|
241
253
|
if response.status != 200:
|
|
242
254
|
content = await safe_read_json_or_text(response)
|
|
243
255
|
logger.warning(f"[Hunter] Non-200 status: {response.status} => {content}")
|
|
244
|
-
|
|
256
|
+
|
|
257
|
+
final_response = {
|
|
245
258
|
"email": email_id,
|
|
246
259
|
"confidence": "low",
|
|
247
260
|
"is_valid": False
|
|
248
261
|
}
|
|
262
|
+
cache_output("hunter_validate", cache_key, [json.dumps(final_response)])
|
|
263
|
+
return final_response
|
|
249
264
|
|
|
250
265
|
result = await response.json()
|
|
251
266
|
except Exception as ex:
|
|
@@ -266,6 +281,7 @@ async def check_email_validity_with_hunter(
|
|
|
266
281
|
"confidence": confidence,
|
|
267
282
|
"is_valid": is_valid
|
|
268
283
|
}
|
|
284
|
+
cache_output("hunter_validate", cache_key, [json.dumps(final_response)])
|
|
269
285
|
logger.info("Exiting check_email_validity_with_hunter.")
|
|
270
286
|
return final_response
|
|
271
287
|
|
|
@@ -162,7 +162,7 @@ async def get_clean_lead_info_with_llm(lead_info_str: str, tool_config: Optional
|
|
|
162
162
|
lead_info, status = await get_structured_output_internal(
|
|
163
163
|
prompt,
|
|
164
164
|
BasicLeadInformation,
|
|
165
|
-
model="gpt-
|
|
165
|
+
model="gpt-4.1",
|
|
166
166
|
tool_config=tool_config
|
|
167
167
|
)
|
|
168
168
|
if status == "ERROR":
|
|
@@ -411,7 +411,7 @@ async def get_user_linkedin_url_from_github_profile(
|
|
|
411
411
|
response, status = await get_structured_output_internal(
|
|
412
412
|
instructions,
|
|
413
413
|
UserInfoFromGithubProfileId,
|
|
414
|
-
model="gpt-
|
|
414
|
+
model="gpt-4.1",
|
|
415
415
|
use_web_search=True,
|
|
416
416
|
tool_config=tool_config
|
|
417
417
|
)
|
|
@@ -783,7 +783,7 @@ async def get_company_domain_from_llm_web_search(
|
|
|
783
783
|
response, status = await get_structured_output_internal(
|
|
784
784
|
instructions,
|
|
785
785
|
CompanyInfoFromName,
|
|
786
|
-
model="gpt-
|
|
786
|
+
model="gpt-4.1",
|
|
787
787
|
use_web_search=True,
|
|
788
788
|
tool_config=tool_config
|
|
789
789
|
)
|
|
@@ -133,6 +133,7 @@ async def generate_personalized_email_copy(
|
|
|
133
133
|
- Do not include PII or internal references, guids or content identifiers in the email.
|
|
134
134
|
- User conversational name for company name if used.
|
|
135
135
|
- Email has saluation Hi <First Name>, unless otherwise specified.
|
|
136
|
+
- <First Name> is the first name of the lead. Its conversational name. It does not have any special characters or spaces.
|
|
136
137
|
"""
|
|
137
138
|
|
|
138
139
|
# Check if a vector store is available
|
|
@@ -106,6 +106,10 @@ async def generate_inbound_email_response_copy(
|
|
|
106
106
|
DO NOT share any link to internal or made up doucment. You can attach or send any document.
|
|
107
107
|
If the user is asking for any document point them to organization's website found in sender information if available:
|
|
108
108
|
{campaign_context.sender_info.model_dump()}
|
|
109
|
+
|
|
110
|
+
Use conversational name for company name.
|
|
111
|
+
Use conversational name when using lead first name.
|
|
112
|
+
Do not use special characters or spaces when use leads first name.
|
|
109
113
|
|
|
110
114
|
Your final output must be valid JSON with the structure:
|
|
111
115
|
{{
|
{dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/generate_linkedin_connect_message.py
RENAMED
|
@@ -25,7 +25,6 @@ from dhisana.utils.assistant_tool_tag import assistant_tool
|
|
|
25
25
|
# LinkedIn Connection Message Schema
|
|
26
26
|
# ----------------------------------------------------------------------
|
|
27
27
|
class LinkedInConnectMessage(BaseModel):
|
|
28
|
-
subject: str
|
|
29
28
|
body: str
|
|
30
29
|
|
|
31
30
|
# ----------------------------------------------------------------------
|
|
@@ -125,11 +124,12 @@ async def generate_personalized_linkedin_copy(
|
|
|
125
124
|
LinkedIn Thread: {conversation_data.current_linkedin_thread or ''}
|
|
126
125
|
|
|
127
126
|
IMPORTANT REQUIREMENTS:
|
|
128
|
-
- Output must be JSON
|
|
129
|
-
- The entire message must be under 40 words total
|
|
127
|
+
- Output must be JSON "body" of the message.
|
|
128
|
+
- The entire message body must be under 40 words total.
|
|
130
129
|
- No placeholders or extra instructions in the final output.
|
|
131
130
|
- Do not include personal addresses, IDs, or irrelevant internal data.
|
|
132
131
|
- Linked in message always has saluatation Hi <First Name>, unless specified otherwise.
|
|
132
|
+
- <First Name> is the first name of the lead. Its conversational name. It does not have any special characters or spaces.
|
|
133
133
|
- User conversational name for company name if used.
|
|
134
134
|
"""
|
|
135
135
|
|
|
@@ -166,7 +166,7 @@ async def generate_personalized_linkedin_copy(
|
|
|
166
166
|
receiver_name=lead_data.full_name or "",
|
|
167
167
|
receiver_email=lead_data.email or "",
|
|
168
168
|
iso_datetime=datetime.utcnow().isoformat(),
|
|
169
|
-
subject=
|
|
169
|
+
subject="Hi",
|
|
170
170
|
body=response_data.body
|
|
171
171
|
)
|
|
172
172
|
|
|
@@ -69,9 +69,24 @@ async def generate_linkedin_response_message_copy(
|
|
|
69
69
|
]
|
|
70
70
|
|
|
71
71
|
cleaned_context = cleanup_reply_linkedin_context(linkedin_context)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
|
|
73
|
+
# Safely handle the current_conversation_context if it exists.
|
|
74
|
+
if cleaned_context.current_conversation_context:
|
|
75
|
+
if not cleaned_context.current_conversation_context.current_email_thread:
|
|
76
|
+
cleaned_context.current_conversation_context.current_email_thread = []
|
|
77
|
+
|
|
78
|
+
if not cleaned_context.current_conversation_context.current_linkedin_thread:
|
|
79
|
+
cleaned_context.current_conversation_context.current_linkedin_thread = []
|
|
80
|
+
|
|
81
|
+
# Safely extract the conversation thread for prompt formatting.
|
|
82
|
+
conversation_thread_dump = [
|
|
83
|
+
thread_item.model_dump()
|
|
84
|
+
for thread_item in cleaned_context.current_conversation_context.current_linkedin_thread
|
|
85
|
+
]
|
|
86
|
+
else:
|
|
87
|
+
# If current_conversation_context is None, use an empty thread.
|
|
88
|
+
conversation_thread_dump = []
|
|
89
|
+
|
|
75
90
|
current_date_iso = datetime.datetime.now().isoformat()
|
|
76
91
|
prompt = f"""
|
|
77
92
|
You are a specialized LinkedIn assistant.
|
|
@@ -89,7 +104,7 @@ async def generate_linkedin_response_message_copy(
|
|
|
89
104
|
{variation}
|
|
90
105
|
|
|
91
106
|
1. Understand the conversation thread:
|
|
92
|
-
{
|
|
107
|
+
{conversation_thread_dump}
|
|
93
108
|
|
|
94
109
|
2. User & Company (Lead) Info:
|
|
95
110
|
{cleaned_context.model_dump()}
|
{dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openai_assistant_and_file_utils.py
RENAMED
|
@@ -190,7 +190,7 @@ async def delete_files(
|
|
|
190
190
|
async def run_file_search(
|
|
191
191
|
query: str,
|
|
192
192
|
vector_store_id: str,
|
|
193
|
-
model: str = "gpt-
|
|
193
|
+
model: str = "gpt-4.1",
|
|
194
194
|
max_num_results: int = 5,
|
|
195
195
|
store: bool = True,
|
|
196
196
|
tool_config: Optional[List[Dict]] = None
|
|
@@ -260,7 +260,7 @@ async def run_file_search(
|
|
|
260
260
|
|
|
261
261
|
async def run_response_text(
|
|
262
262
|
prompt: str,
|
|
263
|
-
model: str = "gpt-
|
|
263
|
+
model: str = "gpt-4.1",
|
|
264
264
|
max_tokens: int = 2048,
|
|
265
265
|
store: bool = True,
|
|
266
266
|
tool_config: Optional[List[Dict]] = None
|
|
@@ -288,7 +288,7 @@ async def run_response_text(
|
|
|
288
288
|
async def run_response_structured(
|
|
289
289
|
prompt: str,
|
|
290
290
|
response_format: dict,
|
|
291
|
-
model: str = "gpt-
|
|
291
|
+
model: str = "gpt-4.1",
|
|
292
292
|
max_tokens: int = 1024,
|
|
293
293
|
store: bool = True,
|
|
294
294
|
tool_config: Optional[List[Dict]] = None
|
|
@@ -8,6 +8,23 @@ def clean_nul_bytes(s: str) -> str:
|
|
|
8
8
|
s = s.replace('```markdown', '')
|
|
9
9
|
return s.replace('\x00', '')
|
|
10
10
|
|
|
11
|
+
def _remove_excluded_fields(data: Dict) -> Dict:
|
|
12
|
+
"""
|
|
13
|
+
Return a copy of `data` that excludes keys named 'id'
|
|
14
|
+
or that end in '_by', '_id', '_to', or '_at'.
|
|
15
|
+
"""
|
|
16
|
+
excluded_keys = {"id"}
|
|
17
|
+
excluded_endings = ["_by", "_id", "_to", "_at", "_status", "research_summary"]
|
|
18
|
+
|
|
19
|
+
cleaned = {}
|
|
20
|
+
for k, v in data.items():
|
|
21
|
+
if k in excluded_keys:
|
|
22
|
+
continue
|
|
23
|
+
if any(k.endswith(suffix) for suffix in excluded_endings):
|
|
24
|
+
continue
|
|
25
|
+
cleaned[k] = v
|
|
26
|
+
return cleaned
|
|
27
|
+
|
|
11
28
|
class LeadResearchInformation(BaseModel):
|
|
12
29
|
research_summary: str
|
|
13
30
|
|
|
@@ -20,7 +37,13 @@ async def research_lead_with_full_info_ai(
|
|
|
20
37
|
"""
|
|
21
38
|
Research on lead provided given input. Provide Detailed Summary.
|
|
22
39
|
"""
|
|
40
|
+
# Clean user properties (e.g. remove newlines, sanitize strings, etc.)
|
|
23
41
|
user_properties = cleanup_email_context(user_properties)
|
|
42
|
+
|
|
43
|
+
# Remove excluded fields from user_properties
|
|
44
|
+
user_properties = _remove_excluded_fields(user_properties)
|
|
45
|
+
|
|
46
|
+
# Optionally remove any known keys that should not appear (e.g. 'date_extracted')
|
|
24
47
|
user_properties.pop("date_extracted", None)
|
|
25
48
|
|
|
26
49
|
instructions = f"""
|
|
@@ -62,14 +85,14 @@ async def research_lead_with_full_info_ai(
|
|
|
62
85
|
response, status = await get_structured_output_internal(
|
|
63
86
|
instructions,
|
|
64
87
|
LeadResearchInformation,
|
|
65
|
-
model="gpt-
|
|
88
|
+
model="gpt-4.1",
|
|
66
89
|
tool_config=tool_config
|
|
67
90
|
)
|
|
68
91
|
if status == "SUCCESS":
|
|
69
92
|
response.research_summary = clean_nul_bytes(response.research_summary)
|
|
70
93
|
return response.model_dump()
|
|
71
94
|
else:
|
|
72
|
-
{"research_summary"
|
|
95
|
+
return {"research_summary": ""}
|
|
73
96
|
|
|
74
97
|
# --------------------------------------------
|
|
75
98
|
# COMPANY-RELATED MODELS & FUNCTION (FIXED)
|
|
@@ -94,9 +117,12 @@ async def research_company_with_full_info_ai(
|
|
|
94
117
|
Returns:
|
|
95
118
|
dict: The JSON response containing the detailed research summary of the company.
|
|
96
119
|
"""
|
|
120
|
+
# Clean company properties (e.g. remove newlines, sanitize strings, etc.)
|
|
97
121
|
company_properties = cleanup_email_context(company_properties)
|
|
98
122
|
|
|
99
|
-
#
|
|
123
|
+
# Remove excluded fields from company_properties
|
|
124
|
+
company_properties = _remove_excluded_fields(company_properties)
|
|
125
|
+
|
|
100
126
|
instructions = f"""
|
|
101
127
|
Please read the following company information and instructions, then produce a detailed summary of the company in the specified format.
|
|
102
128
|
---
|
|
@@ -130,11 +156,10 @@ async def research_company_with_full_info_ai(
|
|
|
130
156
|
"research_summary": "Detailed summary about the company. The summary should be neatly formatted in GitHub-Flavored Markdown, and include all the key information from the listed sections."
|
|
131
157
|
}}
|
|
132
158
|
"""
|
|
133
|
-
|
|
134
159
|
response, status = await get_structured_output_internal(
|
|
135
|
-
instructions,
|
|
136
|
-
CompanyResearchInformation,
|
|
137
|
-
model="gpt-
|
|
160
|
+
instructions,
|
|
161
|
+
CompanyResearchInformation,
|
|
162
|
+
model="gpt-4.1",
|
|
138
163
|
use_web_search=True,
|
|
139
164
|
tool_config=tool_config
|
|
140
165
|
)
|
|
@@ -142,4 +167,4 @@ async def research_company_with_full_info_ai(
|
|
|
142
167
|
response.research_summary = clean_nul_bytes(response.research_summary)
|
|
143
168
|
return response.model_dump()
|
|
144
169
|
else:
|
|
145
|
-
return {"research_summary"
|
|
170
|
+
return {"research_summary": ""}
|
|
@@ -320,7 +320,7 @@ async def test_connectivity(tool_config: List[Dict[str, Any]]) -> Dict[str, Dict
|
|
|
320
320
|
|
|
321
321
|
# Special handling for openai
|
|
322
322
|
if tool_name == "openai":
|
|
323
|
-
model_name = next((c["value"] for c in config_entries if c["name"] == "modelName"), "gpt-
|
|
323
|
+
model_name = next((c["value"] for c in config_entries if c["name"] == "modelName"), "gpt-4.1")
|
|
324
324
|
reasoning_effort = next((c["value"] for c in config_entries if c["name"] == "reasoningEffort"), "medium")
|
|
325
325
|
results[tool_name] = await test_openai(api_key, model_name, reasoning_effort)
|
|
326
326
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/check_linkedin_url_validity.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/compose_three_step_workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/extract_email_content_for_llm.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/openapi_tool/openapi_tool.py
RENAMED
|
File without changes
|
{dhisana-0.0.1.dev101 → dhisana-0.0.1.dev103}/src/dhisana/utils/parse_linkedin_messages_txt.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|