dhisana 0.0.1.dev231__py3-none-any.whl → 0.0.1.dev232__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dhisana/schemas/sales.py +4 -1
- dhisana/utils/generate_email.py +60 -17
- {dhisana-0.0.1.dev231.dist-info → dhisana-0.0.1.dev232.dist-info}/METADATA +1 -1
- {dhisana-0.0.1.dev231.dist-info → dhisana-0.0.1.dev232.dist-info}/RECORD +7 -7
- {dhisana-0.0.1.dev231.dist-info → dhisana-0.0.1.dev232.dist-info}/WHEEL +0 -0
- {dhisana-0.0.1.dev231.dist-info → dhisana-0.0.1.dev232.dist-info}/entry_points.txt +0 -0
- {dhisana-0.0.1.dev231.dist-info → dhisana-0.0.1.dev232.dist-info}/top_level.txt +0 -0
dhisana/schemas/sales.py
CHANGED
|
@@ -291,10 +291,14 @@ class MessageGenerationInstructions(BaseModel):
|
|
|
291
291
|
Holds the user-supplied instructions for generating the message:
|
|
292
292
|
- instructions_to_generate_message: Plain text or template instructions from the user.
|
|
293
293
|
- prompt_engineering_guidance: (Optional) Extra guidelines for structuring the prompt.
|
|
294
|
+
- allow_html: Whether HTML output is allowed.
|
|
295
|
+
- html_template: Optional HTML scaffolding or guidance.
|
|
294
296
|
"""
|
|
295
297
|
instructions_to_generate_message: Optional[str] = None
|
|
296
298
|
prompt_engineering_guidance: Optional[PromptEngineeringGuidance] = None
|
|
297
299
|
use_cache: Optional[bool] = True
|
|
300
|
+
allow_html: Optional[bool] = False
|
|
301
|
+
html_template: Optional[str] = None
|
|
298
302
|
|
|
299
303
|
class CampaignContext(BaseModel):
|
|
300
304
|
"""
|
|
@@ -938,4 +942,3 @@ class CompanyQueryFilters(BaseModel):
|
|
|
938
942
|
default=None,
|
|
939
943
|
description="Maximum founding year for the organization."
|
|
940
944
|
)
|
|
941
|
-
|
dhisana/utils/generate_email.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# Import necessary modules
|
|
2
|
+
import html as html_lib
|
|
3
|
+
import re
|
|
2
4
|
from typing import Dict, List, Optional
|
|
3
5
|
from pydantic import BaseModel
|
|
4
6
|
|
|
@@ -16,9 +18,22 @@ from pydantic import BaseModel, ConfigDict
|
|
|
16
18
|
class EmailCopy(BaseModel):
|
|
17
19
|
subject: str
|
|
18
20
|
body: str
|
|
21
|
+
body_html: Optional[str] = None
|
|
19
22
|
|
|
20
23
|
model_config = ConfigDict(extra="forbid")
|
|
21
24
|
|
|
25
|
+
|
|
26
|
+
def _html_to_plain_text(html_content: str) -> str:
|
|
27
|
+
"""Simple HTML to text conversion to backfill plain body."""
|
|
28
|
+
if not html_content:
|
|
29
|
+
return ""
|
|
30
|
+
# Remove tags and normalize whitespace
|
|
31
|
+
text = re.sub(r"<[^>]+>", " ", html_content)
|
|
32
|
+
text = html_lib.unescape(text)
|
|
33
|
+
# Collapse repeated whitespace/newlines
|
|
34
|
+
lines = [line.strip() for line in text.splitlines()]
|
|
35
|
+
return "\n".join([line for line in lines if line])
|
|
36
|
+
|
|
22
37
|
# -----------------------------------------------------------------------------
|
|
23
38
|
# Utility to Clean Up Context (if needed)
|
|
24
39
|
# -----------------------------------------------------------------------------
|
|
@@ -89,6 +104,42 @@ async def generate_personalized_email_copy(
|
|
|
89
104
|
campaign_data = cleaned_context.campaign_context or CampaignContext()
|
|
90
105
|
conversation_data = cleaned_context.current_conversation_context or ConversationContext()
|
|
91
106
|
|
|
107
|
+
html_note = (
|
|
108
|
+
f"\n Provide the HTML body using this guidance/template when possible:\n {message_instructions.html_template}"
|
|
109
|
+
if getattr(message_instructions, "html_template", None)
|
|
110
|
+
else ""
|
|
111
|
+
)
|
|
112
|
+
important_requirements = """
|
|
113
|
+
IMPORTANT REQUIREMENTS:
|
|
114
|
+
- Output must be JSON with "subject", "body", and "body_html" fields.
|
|
115
|
+
- "body_html" should be clean HTML suitable for email (no external assets), inline styles welcome.
|
|
116
|
+
- "body" must be the plain-text equivalent of "body_html".
|
|
117
|
+
- Keep it concise and relevant. No placeholders or extra instructions.
|
|
118
|
+
- Do not include PII or internal references, guids or content identifiers in the email.
|
|
119
|
+
- Use conversational names for company/person placeholders when provided.
|
|
120
|
+
- Email has salutation Hi <First Name>, unless otherwise specified.
|
|
121
|
+
- Make sure the signature in body has the sender_first_name correct and in the format the user specified.
|
|
122
|
+
- Do Not Make up information. use the information provided in the context and instructions only.
|
|
123
|
+
- Do Not use em dash in the generated output.
|
|
124
|
+
"""
|
|
125
|
+
if not getattr(message_instructions, "allow_html", False):
|
|
126
|
+
important_requirements = """
|
|
127
|
+
IMPORTANT REQUIREMENTS:
|
|
128
|
+
- Output must be JSON with "subject" and "body" fields only.
|
|
129
|
+
- In the subject or body DO NOT include any HTML tags like <a>, <b>, <i>, etc.
|
|
130
|
+
- The body and subject should be in plain text.
|
|
131
|
+
- If there is a link provided in email use it as is. dont wrap it in any HTML tags.
|
|
132
|
+
- Keep it concise and relevant. No placeholders or extra instructions.
|
|
133
|
+
- Do not include PII or internal references, guids or content identifiers in the email.
|
|
134
|
+
- User conversational name for company name if used.
|
|
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.
|
|
137
|
+
- Make sure the signature in body has the sender_first_name is correct and in the format user has specified.
|
|
138
|
+
- Do Not Make up information. use the information provided in the context and instructions only.
|
|
139
|
+
- Make sure the body text is well-formatted and that newline and carriage-return characters are correctly present and preserved in the message body.
|
|
140
|
+
- Do Not use em dash in the generated output.
|
|
141
|
+
"""
|
|
142
|
+
|
|
92
143
|
# Construct the consolidated prompt
|
|
93
144
|
initial_prompt = f"""
|
|
94
145
|
Hi AI Assistant,
|
|
@@ -114,7 +165,7 @@ async def generate_personalized_email_copy(
|
|
|
114
165
|
Triage Guidelines (LinkedIn): {campaign_data.linkedin_triage_guidelines or ''}
|
|
115
166
|
|
|
116
167
|
4) Messaging Instructions (template/framework):
|
|
117
|
-
{selected_instructions}
|
|
168
|
+
{selected_instructions}{html_note}
|
|
118
169
|
|
|
119
170
|
5) External Data / Vector Store:
|
|
120
171
|
(I will be provided with file_search tool if present.)
|
|
@@ -123,21 +174,7 @@ async def generate_personalized_email_copy(
|
|
|
123
174
|
Email Thread: {conversation_data.current_email_thread or ''}
|
|
124
175
|
LinkedIn Thread: {conversation_data.current_linkedin_thread or ''}
|
|
125
176
|
|
|
126
|
-
|
|
127
|
-
- Output must be JSON with "subject" and "body" fields only.
|
|
128
|
-
- In the subject or body DO NOT include any HTML tags like <a>, <b>, <i>, etc.
|
|
129
|
-
- The body and subject should be in plain text.
|
|
130
|
-
- If there is a link provided in email use it as is. dont wrap it in any HTML tags.
|
|
131
|
-
- Keep it concise and relevant. No placeholders or extra instructions.
|
|
132
|
-
- Do not include PII or internal references, guids or content identifiers in the email.
|
|
133
|
-
- User conversational name for company name if used.
|
|
134
|
-
- Email has saluation Hi <First Name>, unless otherwise specified.
|
|
135
|
-
- <First Name> is the first name of the lead. Its conversational name. It does not have any special characters or spaces.
|
|
136
|
-
- Make sure the signature in body has the sender_first_name is correct and in the format user has specified.
|
|
137
|
-
- Do Not Make up information. use the information provided in the context and instructions only.
|
|
138
|
-
- Make sure the body text is well-formatted and that newline and carriage-return characters are correctly present and preserved in the message body.
|
|
139
|
-
- Do Not use em dash in the generated output.
|
|
140
|
-
|
|
177
|
+
{important_requirements}
|
|
141
178
|
"""
|
|
142
179
|
|
|
143
180
|
# Check if a vector store is available
|
|
@@ -169,6 +206,11 @@ async def generate_personalized_email_copy(
|
|
|
169
206
|
|
|
170
207
|
if initial_status != "SUCCESS":
|
|
171
208
|
raise Exception("Error: Could not generate initial draft for the personalized email.")
|
|
209
|
+
plain_body = initial_response.body
|
|
210
|
+
html_body = getattr(initial_response, "body_html", None)
|
|
211
|
+
if not plain_body and html_body:
|
|
212
|
+
plain_body = _html_to_plain_text(html_body)
|
|
213
|
+
|
|
172
214
|
response_item = MessageItem(
|
|
173
215
|
message_id="", # or some real ID if you have it
|
|
174
216
|
thread_id="",
|
|
@@ -178,7 +220,8 @@ async def generate_personalized_email_copy(
|
|
|
178
220
|
receiver_email=email_context.lead_info.email or "",
|
|
179
221
|
iso_datetime=datetime.utcnow().isoformat(),
|
|
180
222
|
subject=initial_response.subject,
|
|
181
|
-
body=
|
|
223
|
+
body=plain_body,
|
|
224
|
+
html_body=html_body if getattr(message_instructions, "allow_html", False) else None,
|
|
182
225
|
)
|
|
183
226
|
return response_item.model_dump()
|
|
184
227
|
|
|
@@ -6,7 +6,7 @@ dhisana/cli/models.py,sha256=IzUFZW_X32mL3fpM1_j4q8AF7v5nrxJcxBoqvG-TTgA,706
|
|
|
6
6
|
dhisana/cli/predictions.py,sha256=VYgoLK1Ksv6MFImoYZqjQJkds7e5Hso65dHwbxTNNzE,646
|
|
7
7
|
dhisana/schemas/__init__.py,sha256=jv2YF__bseklT3OWEzlqJ5qE24c4aWd5F4r0TTjOrWQ,65
|
|
8
8
|
dhisana/schemas/common.py,sha256=SI6nldyfvZhNhfJwy2Qo1VJ7xwuAlg4QHYGLWPoVvZo,9287
|
|
9
|
-
dhisana/schemas/sales.py,sha256=
|
|
9
|
+
dhisana/schemas/sales.py,sha256=k-ZTB-DaQbjvI882L6443H4gspWBFY-VrY2_1xlLn74,33587
|
|
10
10
|
dhisana/ui/__init__.py,sha256=jv2YF__bseklT3OWEzlqJ5qE24c4aWd5F4r0TTjOrWQ,65
|
|
11
11
|
dhisana/ui/components.py,sha256=4NXrAyl9tx2wWwoVYyABO-EOGnreGMvql1AkXWajIIo,14316
|
|
12
12
|
dhisana/utils/__init__.py,sha256=jv2YF__bseklT3OWEzlqJ5qE24c4aWd5F4r0TTjOrWQ,65
|
|
@@ -38,7 +38,7 @@ dhisana/utils/fetch_openai_config.py,sha256=LjWdFuUeTNeAW106pb7DLXZNElos2PlmXRe6
|
|
|
38
38
|
dhisana/utils/field_validators.py,sha256=BZgNCpBG264aRqNUu_J67c6zfr15zlAaIw2XRy8J7DY,11809
|
|
39
39
|
dhisana/utils/g2_tools.py,sha256=a4vmBYCBvLae5CdpOhMN1oNlvO8v9J1B5Sd8T5PzuU8,3346
|
|
40
40
|
dhisana/utils/generate_content.py,sha256=1ycqHhxuxXnsX_5CNp5M6zW40VsM6toYMCwJU9jf__4,2111
|
|
41
|
-
dhisana/utils/generate_email.py,sha256=
|
|
41
|
+
dhisana/utils/generate_email.py,sha256=YUhrku9meo3ee5Ft2ybtLTUTAfUf4quPmJp9hmSkdzM,12895
|
|
42
42
|
dhisana/utils/generate_email_response.py,sha256=3pggNoJKwZ0bAZ3aKaelw7Qip7AsySh16Qw_36Q0Mh4,21212
|
|
43
43
|
dhisana/utils/generate_flow.py,sha256=QMn6bWo0nH0fBvy2Ebub1XfH5udnVAqsPsbIqCtQPXU,4728
|
|
44
44
|
dhisana/utils/generate_leads_salesnav.py,sha256=AONP1KXDJdg95JQBmKx5PQXUD2BHctc-MZOMuRfuK9U,12156
|
|
@@ -93,8 +93,8 @@ dhisana/workflow/agent.py,sha256=esv7_i_XuMkV2j1nz_UlsHov_m6X5WZZiZm_tG4OBHU,565
|
|
|
93
93
|
dhisana/workflow/flow.py,sha256=xWE3qQbM7j2B3FH8XnY3zOL_QXX4LbTW4ArndnEYJE0,1638
|
|
94
94
|
dhisana/workflow/task.py,sha256=HlWz9mtrwLYByoSnePOemBUBrMEcj7KbgNjEE1oF5wo,1830
|
|
95
95
|
dhisana/workflow/test.py,sha256=E7lRnXK0PguTNzyasHytLzTJdkqIPxG5_4qk4hMEeKc,3399
|
|
96
|
-
dhisana-0.0.1.
|
|
97
|
-
dhisana-0.0.1.
|
|
98
|
-
dhisana-0.0.1.
|
|
99
|
-
dhisana-0.0.1.
|
|
100
|
-
dhisana-0.0.1.
|
|
96
|
+
dhisana-0.0.1.dev232.dist-info/METADATA,sha256=RceG6DFxX8ctp-wWTECxTC_saDy69bTzmnB1FdWyf_I,1190
|
|
97
|
+
dhisana-0.0.1.dev232.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
98
|
+
dhisana-0.0.1.dev232.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
|
|
99
|
+
dhisana-0.0.1.dev232.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
|
|
100
|
+
dhisana-0.0.1.dev232.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|