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.
Files changed (102) hide show
  1. dhisana/__init__.py +1 -0
  2. dhisana/cli/__init__.py +1 -0
  3. dhisana/cli/cli.py +20 -0
  4. dhisana/cli/datasets.py +27 -0
  5. dhisana/cli/models.py +26 -0
  6. dhisana/cli/predictions.py +20 -0
  7. dhisana/schemas/__init__.py +1 -0
  8. dhisana/schemas/common.py +399 -0
  9. dhisana/schemas/sales.py +965 -0
  10. dhisana/ui/__init__.py +1 -0
  11. dhisana/ui/components.py +472 -0
  12. dhisana/utils/__init__.py +1 -0
  13. dhisana/utils/add_mapping.py +352 -0
  14. dhisana/utils/agent_tools.py +51 -0
  15. dhisana/utils/apollo_tools.py +1597 -0
  16. dhisana/utils/assistant_tool_tag.py +4 -0
  17. dhisana/utils/built_with_api_tools.py +282 -0
  18. dhisana/utils/cache_output_tools.py +98 -0
  19. dhisana/utils/cache_output_tools_local.py +78 -0
  20. dhisana/utils/check_email_validity_tools.py +717 -0
  21. dhisana/utils/check_for_intent_signal.py +107 -0
  22. dhisana/utils/check_linkedin_url_validity.py +209 -0
  23. dhisana/utils/clay_tools.py +43 -0
  24. dhisana/utils/clean_properties.py +135 -0
  25. dhisana/utils/company_utils.py +60 -0
  26. dhisana/utils/compose_salesnav_query.py +259 -0
  27. dhisana/utils/compose_search_query.py +759 -0
  28. dhisana/utils/compose_three_step_workflow.py +234 -0
  29. dhisana/utils/composite_tools.py +137 -0
  30. dhisana/utils/dataframe_tools.py +237 -0
  31. dhisana/utils/domain_parser.py +45 -0
  32. dhisana/utils/email_body_utils.py +72 -0
  33. dhisana/utils/email_parse_helpers.py +132 -0
  34. dhisana/utils/email_provider.py +375 -0
  35. dhisana/utils/enrich_lead_information.py +933 -0
  36. dhisana/utils/extract_email_content_for_llm.py +101 -0
  37. dhisana/utils/fetch_openai_config.py +129 -0
  38. dhisana/utils/field_validators.py +426 -0
  39. dhisana/utils/g2_tools.py +104 -0
  40. dhisana/utils/generate_content.py +41 -0
  41. dhisana/utils/generate_custom_message.py +271 -0
  42. dhisana/utils/generate_email.py +278 -0
  43. dhisana/utils/generate_email_response.py +465 -0
  44. dhisana/utils/generate_flow.py +102 -0
  45. dhisana/utils/generate_leads_salesnav.py +303 -0
  46. dhisana/utils/generate_linkedin_connect_message.py +224 -0
  47. dhisana/utils/generate_linkedin_response_message.py +317 -0
  48. dhisana/utils/generate_structured_output_internal.py +462 -0
  49. dhisana/utils/google_custom_search.py +267 -0
  50. dhisana/utils/google_oauth_tools.py +727 -0
  51. dhisana/utils/google_workspace_tools.py +1294 -0
  52. dhisana/utils/hubspot_clearbit.py +96 -0
  53. dhisana/utils/hubspot_crm_tools.py +2440 -0
  54. dhisana/utils/instantly_tools.py +149 -0
  55. dhisana/utils/linkedin_crawler.py +168 -0
  56. dhisana/utils/lusha_tools.py +333 -0
  57. dhisana/utils/mailgun_tools.py +156 -0
  58. dhisana/utils/mailreach_tools.py +123 -0
  59. dhisana/utils/microsoft365_tools.py +455 -0
  60. dhisana/utils/openai_assistant_and_file_utils.py +267 -0
  61. dhisana/utils/openai_helpers.py +977 -0
  62. dhisana/utils/openapi_spec_to_tools.py +45 -0
  63. dhisana/utils/openapi_tool/__init__.py +1 -0
  64. dhisana/utils/openapi_tool/api_models.py +633 -0
  65. dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +271 -0
  66. dhisana/utils/openapi_tool/openapi_tool.py +319 -0
  67. dhisana/utils/parse_linkedin_messages_txt.py +100 -0
  68. dhisana/utils/profile.py +37 -0
  69. dhisana/utils/proxy_curl_tools.py +1226 -0
  70. dhisana/utils/proxycurl_search_leads.py +426 -0
  71. dhisana/utils/python_function_to_tools.py +83 -0
  72. dhisana/utils/research_lead.py +176 -0
  73. dhisana/utils/sales_navigator_crawler.py +1103 -0
  74. dhisana/utils/salesforce_crm_tools.py +477 -0
  75. dhisana/utils/search_router.py +131 -0
  76. dhisana/utils/search_router_jobs.py +51 -0
  77. dhisana/utils/sendgrid_tools.py +162 -0
  78. dhisana/utils/serarch_router_local_business.py +75 -0
  79. dhisana/utils/serpapi_additional_tools.py +290 -0
  80. dhisana/utils/serpapi_google_jobs.py +117 -0
  81. dhisana/utils/serpapi_google_search.py +188 -0
  82. dhisana/utils/serpapi_local_business_search.py +129 -0
  83. dhisana/utils/serpapi_search_tools.py +852 -0
  84. dhisana/utils/serperdev_google_jobs.py +125 -0
  85. dhisana/utils/serperdev_local_business.py +154 -0
  86. dhisana/utils/serperdev_search.py +233 -0
  87. dhisana/utils/smtp_email_tools.py +582 -0
  88. dhisana/utils/test_connect.py +2087 -0
  89. dhisana/utils/trasform_json.py +173 -0
  90. dhisana/utils/web_download_parse_tools.py +189 -0
  91. dhisana/utils/workflow_code_model.py +5 -0
  92. dhisana/utils/zoominfo_tools.py +357 -0
  93. dhisana/workflow/__init__.py +1 -0
  94. dhisana/workflow/agent.py +18 -0
  95. dhisana/workflow/flow.py +44 -0
  96. dhisana/workflow/task.py +43 -0
  97. dhisana/workflow/test.py +90 -0
  98. dhisana-0.0.1.dev243.dist-info/METADATA +43 -0
  99. dhisana-0.0.1.dev243.dist-info/RECORD +102 -0
  100. dhisana-0.0.1.dev243.dist-info/WHEEL +5 -0
  101. dhisana-0.0.1.dev243.dist-info/entry_points.txt +2 -0
  102. dhisana-0.0.1.dev243.dist-info/top_level.txt +1 -0
@@ -0,0 +1,259 @@
1
+ import logging
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ import openai # Remove if not required outside get_structured_output_internal
5
+ from pydantic import BaseModel
6
+
7
+ from dhisana.utils.generate_structured_output_internal import get_structured_output_internal
8
+
9
+ logger = logging.getLogger(__name__)
10
+ logging.basicConfig(level=logging.INFO)
11
+
12
+
13
+ class SalesNavQuery(BaseModel):
14
+ """
15
+ Pydantic model representing the final LinkedIn Sales Navigator URL.
16
+ """
17
+ linkedin_salenav_url_with_query_parameters: str
18
+
19
+
20
+ async def generate_salesnav_people_search_url(
21
+ english_description: str = "",
22
+ user_input_salesnav_url: str = "",
23
+ tool_config: Optional[List[Dict[str, Any]]] = None
24
+ ) -> Dict[str, Any]:
25
+ """
26
+ Generate a single LinkedIn Sales Navigator URL based on the user's plain-English
27
+ description of filters and parameters or a provided Sales Navigator URL.
28
+
29
+ This function leverages an LLM (via get_structured_output_internal) to parse
30
+ the user's requirements (e.g., connection degree, seniority, region, etc.)
31
+ and build a properly encoded Sales Navigator people-search URL.
32
+
33
+ The function handles these scenarios:
34
+ 1. Both `english_description` and `user_input_salesnav_url` are provided.
35
+ 2. Only `user_input_salesnav_url` is provided (no `english_description`).
36
+ 3. Only `english_description` is provided (no `user_input_salesnav_url`).
37
+ 4. Neither is provided -> returns an error.
38
+
39
+ Args:
40
+ english_description: A plain-English description of desired filters
41
+ (e.g., "Find me 2nd-degree connections in the IT industry who changed jobs recently").
42
+ user_input_salesnav_url: If the user has provided a Sales Navigator URL to use. (default "").
43
+ tool_config: Optional list of dictionaries containing configuration details
44
+ for the LLM or related tools.
45
+
46
+ Returns:
47
+ A dictionary with a single key: "linkedin_salenav_url_with_query_parameters".
48
+ This maps to a string containing the fully qualified Sales Navigator URL.
49
+
50
+ Raises:
51
+ ValueError: If neither english_description nor user_input_salesnav_url is provided.
52
+ Exception: If the LLM call fails or cannot generate a valid URL.
53
+ """
54
+
55
+ # Explanation of potential filters to guide the model
56
+ supported_filters_explanation = """
57
+ Sales Navigator filters include (not exhaustive):
58
+ - PAST_COLLEAGUE
59
+ - CURRENT_TITLE
60
+ - PAST_TITLE
61
+ - CURRENT_COMPANY
62
+ - PAST_COMPANY
63
+ - GEOGRAPHY (REGION)
64
+ - INDUSTRY
65
+ - SCHOOL
66
+ - CONNECTION (RELATIONSHIP)
67
+ - CONNECTIONS_OF
68
+ - GROUP
69
+ - COMPANY_HEADCOUNT
70
+ - COMPANY_TYPE
71
+ - SENIORITY_LEVEL
72
+ - YEARS_IN_POSITION
73
+ - YEARS_IN_COMPANY
74
+ - FOLLOWING_YOUR_COMPANY (FOLLOWS_YOUR_COMPANY)
75
+ - VIEWED_YOUR_PROFILE
76
+ - CHANGED_JOBS (RECENTLY_CHANGED_JOBS)
77
+ - POSTED_ON_LINKEDIN
78
+ - MENTIONED_IN_NEWS
79
+ - TECHNOLOGIES_USED
80
+ - ANNUAL_REVENUE
81
+ - LEAD_INTERACTIONS (e.g. Viewed Profile, Messaged)
82
+ - SAVED_LEADS_AND_ACCOUNTS
83
+ - WITH_SHARED_EXPERIENCES
84
+ - FIRST_NAME
85
+ - LAST_NAME
86
+ - FUNCTION
87
+ - YEARS_OF_EXPERIENCE
88
+ - YEARS_AT_CURRENT_COMPANY
89
+ - YEARS_IN_CURRENT_POSITION
90
+ - COMPANY_HEADQUARTERS
91
+ - keywords
92
+ """
93
+
94
+ # System message to guide the LLM
95
+ system_message = (
96
+ "You are a helpful AI Assistant that converts an English description of "
97
+ "LinkedIn Sales Navigator search requirements into a valid LinkedIn Sales Navigator people-search URL. "
98
+ "Your output MUST be a single valid URL with properly encoded parameters. "
99
+ "No extra commentary or text is allowed. If you are unsure about a filter, make your best guess or omit it."
100
+ )
101
+
102
+ # Examples to help the LLM
103
+ few_examples_of_queries = (
104
+ "\n 1. Below is an example search url with filter -- company headcount 11-500, seniority level CXO, Current Job Title Chief Marketing Officer,"
105
+ "Geography United States, Connection 2nd-degree connections, and Recently Changed jobs: \n"
106
+ "\nhttps://www.linkedin.com/sales/search/people?query="
107
+ "(recentSearchParam%3A(id%3A4390717732%2CdoLogHistory%3Atrue)%2Cfilters%3AList((type%3ACOMPANY_HEADCOUNT%2Cvalues%3AList"
108
+ "((id%3AC%2Ctext%3A11-50%2CselectionType%3AINCLUDED)%2C(id%3AD%2Ctext%3A51-200%2CselectionType%3AINCLUDED)%2C(id%3AE%2Ctext%3A201-500%2CselectionType%3AINCLUDED)))"
109
+ "%2C(type%3ASENIORITY_LEVEL%2Cvalues%3AList((id%3A310%2Ctext%3ACXO%2CselectionType%3AINCLUDED)))%2C(type%3AREGION%2Cvalues%3AList"
110
+ "((id%3A103644278%2Ctext%3AUnited%2520States%2CselectionType%3AINCLUDED)))"
111
+ "%2C(type%3ARECENTLY_CHANGED_JOBS%2Cvalues%3AList((id%3ARPC%2Ctext%3AChanged%2520jobs%2CselectionType%3AINCLUDED)))"
112
+ "%2C(type%3ARELATIONSHIP%2Cvalues%3AList((id%3AS%2Ctext%3A2nd%2520degree%2520connections%2CselectionType%3AINCLUDED)))"
113
+ "%2C(type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A716%2Ctext%3AChief%2520Marketing%2520Officer%2CselectionType%3AINCLUDED)))))\n\n"
114
+ "\n 2. Below is Another example search url with filters -- company headcount 201-500, seniority level CXO, Current Job Title Chief Executive Officer,"
115
+ "Geography United States, Connection 1st-degree connections, and Recently Posted on LinkedIn: \n"
116
+ "https://www.linkedin.com/sales/search/people?query="
117
+ "(recentSearchParam%3A(id%3A4390717732%2CdoLogHistory%3Atrue)%2C"
118
+ "filters%3AList((type%3ACOMPANY_HEADCOUNT%2Cvalues%3AList((id%3AE%2Ctext%3A201-500%2CselectionType%3AINCLUDED)))"
119
+ "%2C(type%3ASENIORITY_LEVEL%2Cvalues%3AList((id%3A310%2Ctext%3ACXO%2CselectionType%3AINCLUDED)))"
120
+ "%2C(type%3AREGION%2Cvalues%3AList((id%3A103644278%2Ctext%3AUnited%2520States%2CselectionType%3AINCLUDED)))"
121
+ "%2C(type%3ARELATIONSHIP%2Cvalues%3AList((id%3AF%2Ctext%3A1st%2520degree%2520connections%2CselectionType%3AINCLUDED)))"
122
+ "%2C(type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A8%2Ctext%3AChief%2520Executive%2520Officer%2CselectionType%3AINCLUDED)))"
123
+ "%2C(type%3APOSTED_ON_LINKEDIN%2Cvalues%3AList((id%3ARPOL%2CselectionType%3AINCLUDED)))))&viewAllFilters=true\n"
124
+ "\n3. Below is example to Exclude people who have viewed your profile recently or messaged recently: \n"
125
+ "https://www.linkedin.com/sales/search/people?query=(recentSearchParam%3A(id%3A4395364884%2CdoLogHistory%3Atrue)"
126
+ "%2Cfilters%3AList((type%3ALEAD_INTERACTIONS%2Cvalues%3AList((id%3ALIVP%2Ctext%3AViewed%2520profile%2CselectionType%3AEXCLUDED)"
127
+ "%2C(id%3ALIMP%2Ctext%3AMessaged%2CselectionType%3AEXCLUDED)))"
128
+ "%2C(type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A716%2Ctext%3AChief%2520Marketing%2520Officer%2CselectionType%3AINCLUDED)))))"
129
+ "\n 4. Below is example to exclude people who are in your saved leads or accounts list: \n"
130
+ "https://www.linkedin.com/sales/search/people?query=(recentSearchParam%3A(id%3A4395364884%2CdoLogHistory%3Atrue)%2Cfilters%3A"
131
+ "List((type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A716%2Ctext%3AChief%2520Marketing%2520Officer%2CselectionType%3AINCLUDED)))%2C"
132
+ "(type%3ASAVED_LEADS_AND_ACCOUNTS%2Cvalues%3AList((id%3ASL%2Ctext%3AAll%2520my%2520saved%2520leads%2CselectionType%3AEXCLUDED)%2C"
133
+ "(id%3ASA%2Ctext%3AAll%2520my%2520saved%2520accounts%2CselectionType%3AEXCLUDED)))))"
134
+ "\n 5. Below is example to include people with whom you have shared experiences or is past collegue: \n"
135
+ "https://www.linkedin.com/sales/search/people?query=(recentSearchParam%3A(id%3A4395364884%2CdoLogHistory%3Atrue)%2C"
136
+ "filters%3AList((type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A716%2Ctext%3AChief%2520Marketing%2520Officer%2CselectionType%3AINCLUDED)))%2C"
137
+ "(type%3AWITH_SHARED_EXPERIENCES%2Cvalues%3AList((id%3ACOMM%2Ctext%3AShared%2520experiences%2CselectionType%3AINCLUDED)))%2C"
138
+ "(type%3ARELATIONSHIP%2Cvalues%3AList((id%3AS%2Ctext%3A2nd%2520degree%2520connections%2CselectionType%3AINCLUDED)))"
139
+ "%2C(type%3APAST_COLLEAGUE%2Cvalues%3AList((id%3APCOLL%2CselectionType%3AINCLUDED)))))"
140
+ "\n 6. Below is example to track leads who viewed your profile recently or followed your company page: \n"
141
+ "https://www.linkedin.com/sales/search/people?query="
142
+ "(recentSearchParam%3A(id%3A4395364884%2CdoLogHistory%3Atrue)%2Cfilters%3AList((type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A716%2Ctext%3AChief%2520Marketing%2520Officer%2CselectionType%3AINCLUDED)))"
143
+ "%2C(type%3AVIEWED_YOUR_PROFILE%2Cvalues%3AList((id%3AVYP%2Ctext%3AViewed%2520your%2520profile%2520recently%2CselectionType%3AINCLUDED)))"
144
+ "%2C(type%3AFOLLOWS_YOUR_COMPANY%2Cvalues%3AList((id%3ACF%2CselectionType%3AINCLUDED)))))&viewAllFilters=true"
145
+ "\n 7. Below is example Of somer personal filters like name school industry that can be used: \n"
146
+ "https://www.linkedin.com/sales/search/people?query=(recentSearchParam%3A(id%3A4395364884%2CdoLogHistory%3Atrue)"
147
+ "%2Cfilters%3AList((type%3AREGION%2Cvalues%3AList((id%3A102221843%2Ctext%3ANorth%2520America%2CselectionType%3AINCLUDED)))"
148
+ "%2C(type%3AINDUSTRY%2Cvalues%3AList((id%3A6%2Ctext%3ATechnology%252C%2520Information%2520and%2520Internet%2CselectionType%3AINCLUDED)))"
149
+ "%2C(type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A153%2Ctext%3AChief%2520Technology%2520Officer%2CselectionType%3AINCLUDED)))"
150
+ "%2C(type%3AYEARS_OF_EXPERIENCE%2Cvalues%3AList((id%3A4%2Ctext%3A6%2520to%252010%2520years%2CselectionType%3AINCLUDED)))"
151
+ "%2C(type%3ASCHOOL%2Cvalues%3AList((id%3A1792%2Ctext%3AStanford%2520University%2CselectionType%3AINCLUDED)))"
152
+ "%2C(type%3AFIRST_NAME%2Cvalues%3AList((text%3AJohn%2CselectionType%3AINCLUDED)))%2C(type%3ALAST_NAME%2Cvalues%3A"
153
+ "List((text%3ADoe%2CselectionType%3AINCLUDED)))%2C(type%3AGROUP%2Cvalues%3AList((id%3A5119103%2Ctext%3AMobile%2520Integration%2520Cloud%2520Services%2CselectionType%3AINCLUDED)))))viewAllFilters=true"
154
+ "\n 8. Example of some role related filters you can use like job title, seniority level, years at current company: \n"
155
+ "https://www.linkedin.com/sales/search/people?query=(recentSearchParam%3A(id%3A4395364884%2CdoLogHistory%3Atrue)%2Cfilters"
156
+ "%3AList((type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A153%2Ctext%3AChief%2520Technology%2520Officer%2CselectionType%3AINCLUDED)))"
157
+ "%2C(type%3AFUNCTION%2Cvalues%3AList((id%3A8%2Ctext%3AEngineering%2CselectionType%3AINCLUDED)%2C(id%3A25%2Ctext%3ASales%2CselectionType%3AINCLUDED)"
158
+ "%2C(id%3A15%2Ctext%3AMarketing%2CselectionType%3AINCLUDED)))%2C(type%3ASENIORITY_LEVEL%2Cvalues%3AList((id%3A120%2Ctext%3ASenior%2CselectionType%3AINCLUDED)"
159
+ "%2C(id%3A310%2Ctext%3ACXO%2CselectionType%3AINCLUDED)%2C(id%3A110%2Ctext%3AEntry%2520Level%2CselectionType%3AEXCLUDED)))"
160
+ "%2C(type%3APAST_TITLE%2Cvalues%3AList((id%3A5%2Ctext%3ADirector%2CselectionType%3AINCLUDED)))"
161
+ "%2C(type%3AYEARS_AT_CURRENT_COMPANY%2Cvalues%3AList((id%3A3%2Ctext%3A3%2520to%25205%2520years%2CselectionType%3AINCLUDED)))"
162
+ "%2C(type%3AYEARS_IN_CURRENT_POSITION%2Cvalues%3AList((id%3A3%2Ctext%3A3%2520to%25205%2520years%2CselectionType%3AINCLUDED)))))"
163
+ "\n 9. Example of some lead company related filters you can use like company headcount, company name, previous company etc: \n"
164
+ "https://www.linkedin.com/sales/search/people?query=(recentSearchParam%3A(id%3A4395364884%2CdoLogHistory%3Atrue)%2Cfilters%3Ac"
165
+ "List((type%3ACURRENT_TITLE%2Cvalues%3AList((id%3A136%2Ctext%3AVice%2520President%2520of%2520Sales%2CselectionType%3AINCLUDED)))"
166
+ "%2C(type%3ACURRENT_COMPANY%2Cvalues%3AList((id%3Aurn%253Ali%253Aorganization%253A5289249%2Ctext%3AArangoDB%2CselectionType%3AINCLUDED%2Cparent%3A(id%3A0))))"
167
+ "%2C(type%3ACOMPANY_HEADCOUNT%2Cvalues%3AList((id%3AD%2Ctext%3A51-200%2CselectionType%3AINCLUDED)%2C(id%3AC%2Ctext%3A11-50%2CselectionType%3AINCLUDED)))"
168
+ "%2C(type%3APAST_COMPANY%2Cvalues%3AList((id%3Aurn%253Ali%253Aorganization%253A828370%2Ctext%3ANeo4j%2CselectionType%3AINCLUDED%2Cparent%3A(id%3A0))))"
169
+ "%2C(type%3ACOMPANY_TYPE%2Cvalues%3AList((id%3AP%2Ctext%3APrivately%2520Held%2CselectionType%3AINCLUDED)%2C(id%3AC%2Ctext%3APublic%2520Company%2CselectionType%3AINCLUDED)))"
170
+ "%2C(type%3ACOMPANY_HEADQUARTERS%2Cvalues%3AList((id%3A103644278%2Ctext%3AUnited%2520States%2CselectionType%3AINCLUDED)))))"
171
+ "Below is example of using custom keywords to search for people having neo4j in profile: \n"
172
+ "https://www.linkedin.com/sales/search/people?query=(spellCorrectionEnabled%3Atrue%2Ckeywords%3Aneo4j)\n"
173
+ )
174
+
175
+
176
+ # 1. Validate presence of input
177
+ if not english_description and not user_input_salesnav_url:
178
+ raise ValueError("Error: Neither english_description nor user_input_salesnav_url was provided.")
179
+
180
+ # 2. Build the user_prompt conditionally
181
+ if english_description and user_input_salesnav_url:
182
+ # Case 1: Both present
183
+ user_prompt = f"""
184
+ {system_message}
185
+
186
+ The user wants to build a Sales Navigator people-search URL for LinkedIn.
187
+ They have described the desired filters in plain English as follows:
188
+ "{english_description}"
189
+
190
+ Sales navigator URL provided by user:
191
+ {user_input_salesnav_url}
192
+
193
+ The supported filters are described below (for your reference):
194
+ {supported_filters_explanation}
195
+
196
+ Some example URLs:
197
+ {few_examples_of_queries}
198
+
199
+ Do the following step by step:
200
+ 1. Think about the filters required to query the leads.
201
+ 2. Since the user provided a URL, incorporate or validate that URL.
202
+ 3. Look at the examples and supported filters to build the query.
203
+ 4. Make sure the URL generated is valid. Don't make up filters not in the list.
204
+ Double-check to ensure the URL is in valid Sales Navigator format with properly-encoded parameters.
205
+ Output MUST be valid JSON with only 'linkedin_salenav_url_with_query_parameters' as a key.
206
+ """
207
+ elif not english_description and user_input_salesnav_url:
208
+ # Case 2: Only user_input_salesnav_url
209
+ user_prompt = f"""
210
+ {system_message}
211
+
212
+ The user has only provided a Sales Navigator URL to use:
213
+ {user_input_salesnav_url}
214
+
215
+ You do not have an English description of desired filters. Please use or validate
216
+ the provided Sales Navigator URL. The supported filters are described below (for your reference):
217
+ {supported_filters_explanation}
218
+
219
+ Some example URLs:
220
+ {few_examples_of_queries}
221
+
222
+ Output MUST be valid JSON with only 'linkedin_salenav_url_with_query_parameters' as a key.
223
+ """
224
+ else:
225
+ # Case 3: Only english_description
226
+ user_prompt = f"""
227
+ {system_message}
228
+
229
+ They have described the desired filters in plain English as follows:
230
+ "{english_description}"
231
+
232
+ The supported filters are described below (for your reference):
233
+ {supported_filters_explanation}
234
+
235
+ Some example URLs:
236
+ {few_examples_of_queries}
237
+
238
+ Do the following step by step:
239
+ 1. Think about the filters required to query the leads based on the English description.
240
+ 2. Look at the examples and supported filters to build the query.
241
+ 3. Make sure the URL generated is valid. Don't make up filters not in the list.
242
+ Double-check to ensure the URL is in valid Sales Navigator format with properly-encoded parameters.
243
+ Output MUST be valid JSON with only 'linkedin_salenav_url_with_query_parameters' as a key.
244
+ """
245
+
246
+ logger.info("Generating Sales Navigator people-search URL from description: '%s'", english_description)
247
+
248
+ # 3. Call your structured-output helper
249
+ response, status = await get_structured_output_internal(
250
+ user_prompt,
251
+ SalesNavQuery,
252
+ tool_config=tool_config
253
+ )
254
+
255
+ if status != "SUCCESS" or not response:
256
+ raise Exception("Error generating the Sales Navigator URL.")
257
+
258
+ logger.info("Successfully generated Sales Navigator URL.")
259
+ return response.dict()