dhisana 0.0.1.dev226__tar.gz → 0.0.1.dev227__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 (116) hide show
  1. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/PKG-INFO +1 -1
  2. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/setup.py +1 -1
  3. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/google_workspace_tools.py +34 -3
  4. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/smtp_email_tools.py +34 -1
  5. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana.egg-info/PKG-INFO +1 -1
  6. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/README.md +0 -0
  7. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/pyproject.toml +0 -0
  8. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/setup.cfg +0 -0
  9. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/__init__.py +0 -0
  10. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/cli/__init__.py +0 -0
  11. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/cli/cli.py +0 -0
  12. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/cli/datasets.py +0 -0
  13. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/cli/models.py +0 -0
  14. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/cli/predictions.py +0 -0
  15. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/schemas/__init__.py +0 -0
  16. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/schemas/common.py +0 -0
  17. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/schemas/sales.py +0 -0
  18. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/ui/__init__.py +0 -0
  19. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/ui/components.py +0 -0
  20. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/__init__.py +0 -0
  21. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/add_mapping.py +0 -0
  22. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/agent_tools.py +0 -0
  23. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/apollo_tools.py +0 -0
  24. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/assistant_tool_tag.py +0 -0
  25. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/built_with_api_tools.py +0 -0
  26. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/cache_output_tools.py +0 -0
  27. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/cache_output_tools_local.py +0 -0
  28. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/check_email_validity_tools.py +0 -0
  29. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/check_for_intent_signal.py +0 -0
  30. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/check_linkedin_url_validity.py +0 -0
  31. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/clay_tools.py +0 -0
  32. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/clean_properties.py +0 -0
  33. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/company_utils.py +0 -0
  34. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/compose_salesnav_query.py +0 -0
  35. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/compose_search_query.py +0 -0
  36. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
  37. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/composite_tools.py +0 -0
  38. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/dataframe_tools.py +0 -0
  39. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/domain_parser.py +0 -0
  40. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/email_parse_helpers.py +0 -0
  41. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/email_provider.py +0 -0
  42. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/enrich_lead_information.py +0 -0
  43. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
  44. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/fetch_openai_config.py +0 -0
  45. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/field_validators.py +0 -0
  46. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/g2_tools.py +0 -0
  47. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/generate_content.py +0 -0
  48. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/generate_email.py +0 -0
  49. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/generate_email_response.py +0 -0
  50. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/generate_flow.py +0 -0
  51. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
  52. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/generate_linkedin_connect_message.py +0 -0
  53. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/generate_linkedin_response_message.py +0 -0
  54. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/generate_structured_output_internal.py +0 -0
  55. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/google_custom_search.py +0 -0
  56. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/google_oauth_tools.py +0 -0
  57. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/hubspot_clearbit.py +0 -0
  58. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/hubspot_crm_tools.py +0 -0
  59. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/instantly_tools.py +0 -0
  60. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/linkedin_crawler.py +0 -0
  61. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/lusha_tools.py +0 -0
  62. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/mailgun_tools.py +0 -0
  63. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/microsoft365_tools.py +0 -0
  64. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/openai_assistant_and_file_utils.py +0 -0
  65. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/openai_helpers.py +0 -0
  66. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
  67. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
  68. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
  69. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
  70. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
  71. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
  72. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/profile.py +0 -0
  73. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/proxy_curl_tools.py +0 -0
  74. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/proxycurl_search_leads.py +0 -0
  75. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/python_function_to_tools.py +0 -0
  76. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/research_lead.py +0 -0
  77. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
  78. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
  79. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/search_router.py +0 -0
  80. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/search_router_jobs.py +0 -0
  81. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/sendgrid_tools.py +0 -0
  82. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serarch_router_local_business.py +0 -0
  83. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serpapi_additional_tools.py +0 -0
  84. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serpapi_google_jobs.py +0 -0
  85. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serpapi_google_search.py +0 -0
  86. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serpapi_local_business_search.py +0 -0
  87. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serpapi_search_tools.py +0 -0
  88. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serperdev_google_jobs.py +0 -0
  89. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serperdev_local_business.py +0 -0
  90. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/serperdev_search.py +0 -0
  91. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/test_connect.py +0 -0
  92. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/trasform_json.py +0 -0
  93. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/web_download_parse_tools.py +0 -0
  94. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/workflow_code_model.py +0 -0
  95. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/utils/zoominfo_tools.py +0 -0
  96. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/workflow/__init__.py +0 -0
  97. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/workflow/agent.py +0 -0
  98. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/workflow/flow.py +0 -0
  99. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/workflow/task.py +0 -0
  100. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana/workflow/test.py +0 -0
  101. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana.egg-info/SOURCES.txt +0 -0
  102. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana.egg-info/dependency_links.txt +0 -0
  103. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana.egg-info/entry_points.txt +0 -0
  104. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana.egg-info/requires.txt +0 -0
  105. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/src/dhisana.egg-info/top_level.txt +0 -0
  106. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_agent_tools.py +0 -0
  107. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_apollo_company_search.py +0 -0
  108. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_apollo_lead_search.py +0 -0
  109. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_connectivity.py +0 -0
  110. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_google_document.py +0 -0
  111. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_hubspot_call_logs.py +0 -0
  112. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_linkedin_serper.py +0 -0
  113. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_mcp_connectivity.py +0 -0
  114. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_proxycurl_get_company_search_id.py +0 -0
  115. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_proxycurl_job_count.py +0 -0
  116. {dhisana-0.0.1.dev226 → dhisana-0.0.1.dev227}/tests/test_structured_output_with_mcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev226
3
+ Version: 0.0.1.dev227
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
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='dhisana',
5
- version='0.0.1-dev226',
5
+ version='0.0.1-dev227',
6
6
  description='A Python SDK for Dhisana AI Platform',
7
7
  author='Admin',
8
8
  author_email='contact@dhisana.ai',
@@ -1,12 +1,14 @@
1
1
  import base64
2
2
  import csv
3
3
  import datetime
4
+ import html as html_lib
4
5
  import io
5
6
  import json
6
7
  import logging
7
8
  import os
8
9
  import re
9
10
  import uuid
11
+ from email.mime.multipart import MIMEMultipart
10
12
  from email.mime.text import MIMEText
11
13
  from typing import Any, Dict, List, Optional
12
14
 
@@ -109,6 +111,28 @@ def get_google_credentials(
109
111
  return credentials
110
112
 
111
113
 
114
+ def _looks_like_html(text: str) -> bool:
115
+ """Heuristically determine whether the body contains HTML markup."""
116
+ return bool(text and re.search(r"<[a-zA-Z][^>]*>", text))
117
+
118
+
119
+ def _html_to_plain_text(html: str) -> str:
120
+ """
121
+ Produce a very lightweight plain-text version of an HTML fragment.
122
+ This keeps newlines on block boundaries and strips tags.
123
+ """
124
+ if not html:
125
+ return ""
126
+ text = re.sub(r"(?is)<(script|style).*?>.*?</\1>", " ", html)
127
+ text = re.sub(r"(?i)<br\s*/?>", "\n", text)
128
+ text = re.sub(r"(?i)</(p|div|li|h[1-6])\s*>", "\n", text)
129
+ text = re.sub(r"(?is)<.*?>", "", text)
130
+ text = html_lib.unescape(text)
131
+ text = re.sub(r"\s+\n", "\n", text)
132
+ text = re.sub(r"\n{3,}", "\n\n", text)
133
+ return text.strip()
134
+
135
+
112
136
 
113
137
  @assistant_tool
114
138
  async def send_email_using_service_account_async(
@@ -137,8 +161,16 @@ async def send_email_using_service_account_async(
137
161
 
138
162
  gmail_api_url = 'https://gmail.googleapis.com/gmail/v1/users/me/messages/send'
139
163
 
140
- # Construct the MIME text message
141
- message = MIMEText(send_email_context.body)
164
+ body = send_email_context.body or ""
165
+
166
+ if _looks_like_html(body):
167
+ # Gmail prefers multipart/alternative when HTML is present.
168
+ message = MIMEMultipart("alternative")
169
+ message.attach(MIMEText(_html_to_plain_text(body), "plain", _charset="utf-8"))
170
+ message.attach(MIMEText(body, "html", _charset="utf-8"))
171
+ else:
172
+ message = MIMEText(body, _subtype="plain", _charset="utf-8")
173
+
142
174
  message['to'] = send_email_context.recipient
143
175
  message['from'] = f"{send_email_context.sender_name} <{send_email_context.sender_email}>"
144
176
  message['subject'] = send_email_context.subject
@@ -1186,4 +1218,3 @@ def save_values_to_csv(values: List[List[str]], output_filename: str) -> str:
1186
1218
  writer.writerows(values)
1187
1219
 
1188
1220
  return local_file_path
1189
-
@@ -7,12 +7,14 @@ import datetime
7
7
  import email
8
8
  import email.utils
9
9
  import hashlib
10
+ import html as html_lib
10
11
  import imaplib
11
12
  import logging
12
13
  import re
13
14
  import uuid
14
15
  from email.errors import HeaderParseError
15
16
  from email.header import Header, decode_header, make_header
17
+ from email.mime.multipart import MIMEMultipart
16
18
  from email.mime.text import MIMEText
17
19
  from datetime import datetime, timedelta, timezone
18
20
  from typing import Any, Dict, List, Optional, Union
@@ -102,6 +104,28 @@ def _to_datetime(val: Union[datetime, str]) -> datetime:
102
104
  ) from exc
103
105
 
104
106
 
107
+ def _looks_like_html(text: str) -> bool:
108
+ """Heuristically determine whether the body contains HTML markup."""
109
+ return bool(text and re.search(r"<[a-zA-Z][^>]*>", text))
110
+
111
+
112
+ def _html_to_plain_text(html: str) -> str:
113
+ """
114
+ Produce a very lightweight plain-text version of an HTML fragment.
115
+ This keeps newlines on block boundaries and strips tags.
116
+ """
117
+ if not html:
118
+ return ""
119
+ text = re.sub(r"(?is)<(script|style).*?>.*?</\1>", " ", html)
120
+ text = re.sub(r"(?i)<br\s*/?>", "\n", text)
121
+ text = re.sub(r"(?i)</(p|div|li|h[1-6])\s*>", "\n", text)
122
+ text = re.sub(r"(?is)<.*?>", "", text)
123
+ text = html_lib.unescape(text)
124
+ text = re.sub(r"\s+\n", "\n", text)
125
+ text = re.sub(r"\n{3,}", "\n\n", text)
126
+ return text.strip()
127
+
128
+
105
129
  # --------------------------------------------------------------------------- #
106
130
  # Outbound -- SMTP
107
131
  # --------------------------------------------------------------------------- #
@@ -127,7 +151,16 @@ async def send_email_via_smtp_async(
127
151
  str
128
152
  The Message-ID of the sent message (e.g., "<uuid@yourdomain.com>").
129
153
  """
130
- msg = MIMEText(ctx.body, _charset="utf-8")
154
+ body = ctx.body or ""
155
+
156
+ if _looks_like_html(body):
157
+ # Build multipart/alternative so HTML-capable clients see rich content.
158
+ msg = MIMEMultipart("alternative")
159
+ msg.attach(MIMEText(_html_to_plain_text(body), "plain", _charset="utf-8"))
160
+ msg.attach(MIMEText(body, "html", _charset="utf-8"))
161
+ else:
162
+ msg = MIMEText(body, _subtype="plain", _charset="utf-8")
163
+
131
164
  msg["From"] = f"{ctx.sender_name} <{ctx.sender_email}>"
132
165
  msg["To"] = ctx.recipient
133
166
  msg["Subject"] = ctx.subject
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev226
3
+ Version: 0.0.1.dev227
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
File without changes
File without changes