fusesell 1.3.42__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.
- fusesell-1.3.42.dist-info/METADATA +873 -0
- fusesell-1.3.42.dist-info/RECORD +35 -0
- fusesell-1.3.42.dist-info/WHEEL +5 -0
- fusesell-1.3.42.dist-info/entry_points.txt +2 -0
- fusesell-1.3.42.dist-info/licenses/LICENSE +21 -0
- fusesell-1.3.42.dist-info/top_level.txt +2 -0
- fusesell.py +20 -0
- fusesell_local/__init__.py +37 -0
- fusesell_local/api.py +343 -0
- fusesell_local/cli.py +1480 -0
- fusesell_local/config/__init__.py +11 -0
- fusesell_local/config/default_email_templates.json +34 -0
- fusesell_local/config/default_prompts.json +19 -0
- fusesell_local/config/default_scoring_criteria.json +154 -0
- fusesell_local/config/prompts.py +245 -0
- fusesell_local/config/settings.py +277 -0
- fusesell_local/pipeline.py +978 -0
- fusesell_local/stages/__init__.py +19 -0
- fusesell_local/stages/base_stage.py +603 -0
- fusesell_local/stages/data_acquisition.py +1820 -0
- fusesell_local/stages/data_preparation.py +1238 -0
- fusesell_local/stages/follow_up.py +1728 -0
- fusesell_local/stages/initial_outreach.py +2972 -0
- fusesell_local/stages/lead_scoring.py +1452 -0
- fusesell_local/utils/__init__.py +36 -0
- fusesell_local/utils/agent_context.py +552 -0
- fusesell_local/utils/auto_setup.py +361 -0
- fusesell_local/utils/birthday_email_manager.py +467 -0
- fusesell_local/utils/data_manager.py +4857 -0
- fusesell_local/utils/event_scheduler.py +959 -0
- fusesell_local/utils/llm_client.py +342 -0
- fusesell_local/utils/logger.py +203 -0
- fusesell_local/utils/output_helpers.py +2443 -0
- fusesell_local/utils/timezone_detector.py +914 -0
- fusesell_local/utils/validators.py +436 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"initial_outreach": {
|
|
3
|
+
"formal": {
|
|
4
|
+
"greeting": "Dear {recipient_name},",
|
|
5
|
+
"introduction": "I hope this email finds you well. My name is {staff_name} from {org_name}.",
|
|
6
|
+
"value_proposition": "I noticed that {company_name} operates in the {industry} sector, and I believe our solution could help address some of the challenges you might be facing.",
|
|
7
|
+
"call_to_action": "Would you be interested in a brief conversation to explore how we might be able to help?",
|
|
8
|
+
"closing": "Best regards,\n{staff_name}\n{org_name}"
|
|
9
|
+
},
|
|
10
|
+
"casual": {
|
|
11
|
+
"greeting": "Hi {recipient_name},",
|
|
12
|
+
"introduction": "I'm {staff_name} from {org_name}, and I've been following {company_name}'s work in {industry}.",
|
|
13
|
+
"value_proposition": "I think there might be some interesting opportunities for us to collaborate and help you tackle {pain_point}.",
|
|
14
|
+
"call_to_action": "Would you be up for a quick chat to explore this further?",
|
|
15
|
+
"closing": "Cheers,\n{staff_name}"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"follow_up": {
|
|
19
|
+
"no_response": {
|
|
20
|
+
"greeting": "Hi {recipient_name},",
|
|
21
|
+
"reference": "I wanted to follow up on my previous email about {topic}.",
|
|
22
|
+
"value_add": "I thought you might find this relevant: {additional_info}",
|
|
23
|
+
"call_to_action": "If now isn't the right time, I completely understand. Would a different time work better?",
|
|
24
|
+
"closing": "Best,\n{staff_name}"
|
|
25
|
+
},
|
|
26
|
+
"engaged": {
|
|
27
|
+
"greeting": "Hi {recipient_name},",
|
|
28
|
+
"reference": "Thanks for your interest in our previous conversation about {topic}.",
|
|
29
|
+
"next_step": "As discussed, I've prepared some additional information that might be helpful.",
|
|
30
|
+
"call_to_action": "When would be a good time for a more detailed discussion?",
|
|
31
|
+
"closing": "Looking forward to hearing from you,\n{staff_name}"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data_preparation": {
|
|
3
|
+
"extract_company_info": "Analyze the following raw customer data and extract structured company information including name, industry, size, address, and key business details. Format the response as JSON with the following structure: {\"companyInfo\": {\"name\": \"\", \"industry\": \"\", \"size\": \"\", \"address\": \"\", \"website\": \"\", \"annualRevenue\": \"\"}}",
|
|
4
|
+
"identify_pain_points": "Based on the company information provided, identify potential business pain points and challenges. Categorize each pain point by impact area and provide detailed descriptions. Format as JSON array: [{\"category\": \"\", \"impact\": \"\", \"description\": \"\"}]",
|
|
5
|
+
"financial_analysis": "Analyze the financial indicators and company size to estimate revenue, growth potential, and funding sources. Provide structured financial assessment."
|
|
6
|
+
},
|
|
7
|
+
"lead_scoring": {
|
|
8
|
+
"evaluate_fit": "Evaluate how well this customer profile fits our product criteria. Consider company size, industry, pain points, and technology needs. Provide detailed scoring breakdown.",
|
|
9
|
+
"score_calculation": "Calculate a lead score from 0-100 based on the provided criteria and customer data. Show detailed breakdown of scoring factors."
|
|
10
|
+
},
|
|
11
|
+
"initial_outreach": {
|
|
12
|
+
"email_generation": "Create four initial outreach ##action_type## variations in ##language## for ##customer_name## of ##company_name## on behalf of ##staff_name## (sender, from ##org_name##). Guidelines:\n\n1. Use email tones from this list: Professional, Friendly, Urgent, Persuasive, Apologetic, Appreciative, Informative, Collaborative, Assertive, Empathetic. You may use up to two tones if appropriate.\n\n2. For each email variation:\n- Craft an intriguing subject line (max 50 characters) hinting at specific value.\n- Use ONLY recipient's first name in greeting. ##first_name_guide##. For languages other than Vietnamese: Use only the recipient's first name without honorifics. \n- Open with a personalized introduction, including sender's name, position, and company.\n- Demonstrate knowledge of the recipient's company and industry.\n- Establish relevance by mentioning specific challenges or opportunities in their industry.\n- Present a concise value proposition addressing top 2-3 pain points.\n- Highlight key benefits aligned with recipient's needs.\n- Include relevant social proof, mentioning other clients in the same industry.\n- Provide 3-5 bullet points of specific solutions or features tailored to the recipient's needs.\n- Use one of these call-to-action approaches:\na. Simple Interest Check: Ask for a minimal, low-effort reply to express interest\nb. Challenge Inquiry: Invite sharing of specific challenges with an easy reply option\nc. Quick Call Proposal: Suggest a brief, no-pressure call\nd. Specific Question: Ask a relevant, thought-provoking question about their business\ne. Resource Offer: Propose sending a valuable resource (case study, whitepaper, etc.)\n- Include an appropriate closing phrase that matches the email's tone and content, followed by a signature with this format:\n<p>[Closing phrase],\n##staff_name##\n##org_name##</p>\n\n3. Product Mentioning:\n- For half of the variations, explicitly mention the product name and key features.\n- The product to mention should be ##selected_product## (mention this exact name) if provided, or the top-scoring product based on lead_scoring results.\n- For the other half, focus on benefits and pain points without directly naming the product.\n\n4. Use simple HTML formatting (<p>, <strong>, <ul>, <li>) for readability and structure.\n5. Use clear paragraph breaks and bullet points to enhance scannability.\n6. Don't use placeholder text or invent information.\n7. Align with company brand voice and recipient's needs/industry.\n8. Aim for 300-400 words for each email body.\n9. Do not include any hyperlinks or attachments in the email body.\n9. The pronoun must be consistent throughout the draft. Pronoun usage: \n- For Vietnamese language: If pronoun refers to staff name, use ##staff_name## throughout the email\n- For all other languages: Use appropriate first-person pronouns based on the language\n10. DON'T hallucinate, don't make up information. \n\nEnsure diversity across the four variations:\n- Use at least 2 different email tones\n- Use at least 1 different approach methods\n- 2 variations should mention the product name, 2 should not\n\nCreate all 4 variations first, then randomly shuffle their order before assigning priority orders. Return 4 objects in this JSON format:\n[\n{\n\"mail_tone\": \"Recommended tone\",\n\"subject\": \"Subject line\",\n\"body\": \"HTML-formatted email body including signature\",\n\"priority_order\": 1,\n\"approach\": \"Approach method used\",\n\"product_mention\": true/false,\n\"product_name\": \"##selected_product## or top-scoring product if mentioned, else null\",\n\"message_type\": \"Email\",\n\"tags\": [\"Email\", \"MailTone1\", \"MailTone2\", \"ApproachMethod\", \"ProductMentioned/ProductNotMentioned\"]\n}\n]\n\nThe objects MUST be in a random order, not sorted by mail_tone or any other field. Assign priority_order from 1 to 4 AFTER shuffling.\n\nNO REDUNDANT WORDS. NO NEED TO BE WRAPPED IN ``` CODE BLOCK CHARACTERS.\nInput information: ##company_info##\nSelected product information: ##selected_product_info##\n",
|
|
13
|
+
"subject_line": "Create 3 compelling email subject lines for this outreach email that are personalized to the customer and likely to generate opens."
|
|
14
|
+
},
|
|
15
|
+
"follow_up": {
|
|
16
|
+
"analyze_interaction": "Analyze the previous interaction history and determine the best follow-up approach based on customer engagement level and response patterns.",
|
|
17
|
+
"generate_followup": "Create a follow-up {{$node[\"Webhook\"].json.body.interaction_type}} draft in {{$node[\"Webhook\"].json.body.language}} for ##customer_name## from ##staff_name##. Guidelines:\n\n1. Choose tone: Friendly, Informative, or Collaborative.\n\n2. Draft components:\n - Subject line (max 50 chars): Reference previous outreach without mentioning dates\n - Greeting: Use recipient's first name only. ##first_name_guide##\n - Opening: Briefly acknowledge previous contact without specific date\n - Body: \n - Subtly reiterate key value proposition (focus on 1-2 pain points from ##pain_points##)\n - Add new, relevant information based on ##companyInfo##, ##currentTechStack##, or ##developmentPlans##\n - Approach: Gentle Reminder with Additional Value\n - Clear, low-pressure call-to-action (e.g., offer to schedule a brief call or provide more information)\n - Closing: Match email tone\n - Signature: ##staff_name##<br>##org_name##\n\n3. Product mention: If appropriate, reference ##selected_product## or top-scoring product from ##lead_scoring## indirectly by focusing on benefits/solutions\n\n4. Formatting: Simple HTML (<p>, <strong>). No complex HTML, links, or attachments.\n\n5. Style: Align with ##org_name## brand voice and recipient's industry (##companyInfo.industry##). Max 125 words.\n\n6. Don't use placeholder text or invent. information.\n\n7. Don't include any hyperlinks or attachments in the email body.\n\n8. The pronoun must be consistent throughout the draft.\n\n9. DON'T hallucinate, don't make up information. \n\nReturn JSON:\n{\n \"mail_tone\": \"Chosen tone\",\n \"subject\": \"Subject line\",\n \"body\": \"HTML-formatted email body with signature\",\n \"approach\": \"Gentle Reminder with Additional Value\",\n \"product_mention\": true/false,\n \"product_name\": \"Product name if mentioned indirectly, else null\",\n \"message_type\": \"Follow-up Email\",\n \"tags\": [\"Follow-up\", \"MailTone\", \"GentleReminder\", \"AdditionalValue\", \"ProductMentioned/ProductNotMentioned\"]\n}\n\nNO REDUNDANT WORDS. NO NEED TO BE WRAPPED IN ``` CODE BLOCK CHARACTERS.\n\nInput: ##companyInfo##\nProduct info: ##selected_product_info##\nPrevious outreach: ##last_interaction_date##\nSales stage: ##current_sales_stage##\nFollow-up reason: ##follow_up_reason##\nInitial email content: ##sent_content##\n"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scoring_weights": {
|
|
3
|
+
"company_size": 0.25,
|
|
4
|
+
"industry_fit": 0.2,
|
|
5
|
+
"pain_points_match": 0.3,
|
|
6
|
+
"financial_health": 0.15,
|
|
7
|
+
"technology_readiness": 0.1
|
|
8
|
+
},
|
|
9
|
+
"company_size_scores": {
|
|
10
|
+
"startup": 60,
|
|
11
|
+
"small": 70,
|
|
12
|
+
"medium": 85,
|
|
13
|
+
"large": 90,
|
|
14
|
+
"enterprise": 95
|
|
15
|
+
},
|
|
16
|
+
"industry_multipliers": {
|
|
17
|
+
"technology": 1.2,
|
|
18
|
+
"finance": 1.1,
|
|
19
|
+
"healthcare": 1.0,
|
|
20
|
+
"manufacturing": 0.9,
|
|
21
|
+
"retail": 0.8
|
|
22
|
+
},
|
|
23
|
+
"pain_point_categories": {
|
|
24
|
+
"efficiency": 20,
|
|
25
|
+
"cost_reduction": 25,
|
|
26
|
+
"growth": 30,
|
|
27
|
+
"compliance": 15,
|
|
28
|
+
"customer_experience": 20
|
|
29
|
+
},
|
|
30
|
+
"rta": [
|
|
31
|
+
{
|
|
32
|
+
"name": "industry_fit",
|
|
33
|
+
"weight": 25,
|
|
34
|
+
"definition": "How well the customer's industry aligns with the product's target market",
|
|
35
|
+
"guidelines": "Score based on industry match and market presence",
|
|
36
|
+
"scoring_factors": [
|
|
37
|
+
"Perfect industry match: 80-100",
|
|
38
|
+
"Related industry: 60-79",
|
|
39
|
+
"Adjacent industry: 40-59",
|
|
40
|
+
"Unrelated industry: 0-39"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "company_size",
|
|
45
|
+
"weight": 20,
|
|
46
|
+
"definition": "Company size alignment with product's ideal customer profile",
|
|
47
|
+
"guidelines": "Score based on employee count and revenue alignment",
|
|
48
|
+
"scoring_factors": [
|
|
49
|
+
"Ideal size range: 80-100",
|
|
50
|
+
"Close to ideal: 60-79",
|
|
51
|
+
"Acceptable size: 40-59",
|
|
52
|
+
"Poor size fit: 0-39"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "pain_points",
|
|
57
|
+
"weight": 30,
|
|
58
|
+
"definition": "How well the product addresses customer's identified pain points",
|
|
59
|
+
"guidelines": "Score based on pain point alignment and severity",
|
|
60
|
+
"scoring_factors": [
|
|
61
|
+
"Addresses all major pain points: 80-100",
|
|
62
|
+
"Addresses most pain points: 60-79",
|
|
63
|
+
"Addresses some pain points: 40-59",
|
|
64
|
+
"Addresses few/no pain points: 0-39"
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "product_fit",
|
|
69
|
+
"weight": 15,
|
|
70
|
+
"definition": "Overall product-customer compatibility",
|
|
71
|
+
"guidelines": "Score based on feature alignment and use case match",
|
|
72
|
+
"scoring_factors": [
|
|
73
|
+
"Excellent feature match: 80-100",
|
|
74
|
+
"Good feature match: 60-79",
|
|
75
|
+
"Basic feature match: 40-59",
|
|
76
|
+
"Poor feature match: 0-39"
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "geographic_market_fit",
|
|
81
|
+
"weight": 10,
|
|
82
|
+
"definition": "Geographic alignment between customer location and product availability",
|
|
83
|
+
"guidelines": "Score based on market presence and localization",
|
|
84
|
+
"scoring_factors": [
|
|
85
|
+
"Strong market presence: 80-100",
|
|
86
|
+
"Moderate presence: 60-79",
|
|
87
|
+
"Limited presence: 40-59",
|
|
88
|
+
"No market presence: 0-39"
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"rta_enterprise": [
|
|
93
|
+
{
|
|
94
|
+
"name": "budget_authority",
|
|
95
|
+
"weight": 25,
|
|
96
|
+
"definition": "Customer's budget authority and financial capacity",
|
|
97
|
+
"guidelines": "Score based on budget size and decision-making authority",
|
|
98
|
+
"scoring_factors": [
|
|
99
|
+
"Confirmed budget >$100k: 90-100",
|
|
100
|
+
"Estimated budget $50k-$100k: 70-89",
|
|
101
|
+
"Estimated budget $10k-$50k: 40-69",
|
|
102
|
+
"No budget information: 0-39"
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "technical_fit",
|
|
107
|
+
"weight": 20,
|
|
108
|
+
"definition": "Technical requirements alignment with product capabilities",
|
|
109
|
+
"guidelines": "Score based on technical complexity and integration needs",
|
|
110
|
+
"scoring_factors": [
|
|
111
|
+
"Perfect technical match: 80-100",
|
|
112
|
+
"Good match with minor customization: 60-79",
|
|
113
|
+
"Moderate match requiring development: 40-59",
|
|
114
|
+
"Poor technical fit: 0-39"
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "decision_timeline",
|
|
119
|
+
"weight": 15,
|
|
120
|
+
"definition": "Customer's decision-making timeline and urgency",
|
|
121
|
+
"guidelines": "Score based on purchase timeline and urgency indicators",
|
|
122
|
+
"scoring_factors": [
|
|
123
|
+
"Immediate need (0-3 months): 80-100",
|
|
124
|
+
"Near-term need (3-6 months): 60-79",
|
|
125
|
+
"Future need (6-12 months): 40-59",
|
|
126
|
+
"No defined timeline: 0-39"
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "competitive_situation",
|
|
131
|
+
"weight": 20,
|
|
132
|
+
"definition": "Competitive landscape and our positioning",
|
|
133
|
+
"guidelines": "Score based on competitive threats and our advantages",
|
|
134
|
+
"scoring_factors": [
|
|
135
|
+
"No competition, clear leader: 80-100",
|
|
136
|
+
"Preferred vendor, light competition: 60-79",
|
|
137
|
+
"Competitive situation, even playing field: 40-59",
|
|
138
|
+
"Strong competition, uphill battle: 0-39"
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"name": "stakeholder_engagement",
|
|
143
|
+
"weight": 20,
|
|
144
|
+
"definition": "Level of stakeholder engagement and champion strength",
|
|
145
|
+
"guidelines": "Score based on champion strength and stakeholder buy-in",
|
|
146
|
+
"scoring_factors": [
|
|
147
|
+
"Strong champion with executive support: 80-100",
|
|
148
|
+
"Good champion with some support: 60-79",
|
|
149
|
+
"Weak champion or mixed support: 40-59",
|
|
150
|
+
"No champion or opposition: 0-39"
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prompt Manager for FuseSell Local
|
|
3
|
+
Handles LLM prompt templates and variable substitution
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Dict, Any, Optional
|
|
7
|
+
import re
|
|
8
|
+
import logging
|
|
9
|
+
from .settings import ConfigManager
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PromptManager:
|
|
13
|
+
"""
|
|
14
|
+
Manages LLM prompts with template substitution and customization.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config_manager: ConfigManager):
|
|
18
|
+
"""
|
|
19
|
+
Initialize prompt manager.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
config_manager: Configuration manager instance
|
|
23
|
+
"""
|
|
24
|
+
self.config_manager = config_manager
|
|
25
|
+
self.logger = logging.getLogger("fusesell.prompts")
|
|
26
|
+
|
|
27
|
+
def get_prompt(
|
|
28
|
+
self,
|
|
29
|
+
stage: str,
|
|
30
|
+
prompt_key: str,
|
|
31
|
+
variables: Optional[Dict[str, Any]] = None,
|
|
32
|
+
team_id: Optional[str] = None,
|
|
33
|
+
language: str = "english"
|
|
34
|
+
) -> str:
|
|
35
|
+
"""
|
|
36
|
+
Get formatted prompt for a specific stage and key.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
stage: Pipeline stage name
|
|
40
|
+
prompt_key: Specific prompt identifier
|
|
41
|
+
variables: Variables for template substitution
|
|
42
|
+
team_id: Optional team ID for customization
|
|
43
|
+
language: Language for prompts
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Formatted prompt string
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
# Get prompts configuration
|
|
50
|
+
prompts = self.config_manager.get_prompts(team_id, language)
|
|
51
|
+
|
|
52
|
+
# Get stage-specific prompts
|
|
53
|
+
stage_prompts = prompts.get(stage, {})
|
|
54
|
+
if not stage_prompts:
|
|
55
|
+
self.logger.warning(f"No prompts found for stage: {stage}")
|
|
56
|
+
return ""
|
|
57
|
+
|
|
58
|
+
# Get specific prompt template
|
|
59
|
+
prompt_template = stage_prompts.get(prompt_key, "")
|
|
60
|
+
if not prompt_template:
|
|
61
|
+
self.logger.warning(f"No prompt found for {stage}.{prompt_key}")
|
|
62
|
+
return ""
|
|
63
|
+
|
|
64
|
+
# Apply variable substitution
|
|
65
|
+
if variables:
|
|
66
|
+
prompt_template = self._substitute_variables(prompt_template, variables)
|
|
67
|
+
|
|
68
|
+
return prompt_template
|
|
69
|
+
|
|
70
|
+
except Exception as e:
|
|
71
|
+
self.logger.error(f"Failed to get prompt {stage}.{prompt_key}: {str(e)}")
|
|
72
|
+
return ""
|
|
73
|
+
|
|
74
|
+
def get_data_acquisition_prompts(self, variables: Dict[str, Any], **kwargs) -> Dict[str, str]:
|
|
75
|
+
"""Get all prompts for data acquisition stage."""
|
|
76
|
+
return {
|
|
77
|
+
'website_extraction': self.get_prompt('data_acquisition', 'website_extraction', variables, **kwargs),
|
|
78
|
+
'business_card_ocr': self.get_prompt('data_acquisition', 'business_card_ocr', variables, **kwargs),
|
|
79
|
+
'social_media_analysis': self.get_prompt('data_acquisition', 'social_media_analysis', variables, **kwargs),
|
|
80
|
+
'data_consolidation': self.get_prompt('data_acquisition', 'data_consolidation', variables, **kwargs)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
def get_data_preparation_prompts(self, variables: Dict[str, Any], **kwargs) -> Dict[str, str]:
|
|
84
|
+
"""Get all prompts for data preparation stage."""
|
|
85
|
+
return {
|
|
86
|
+
'extract_company_info': self.get_prompt('data_preparation', 'extract_company_info', variables, **kwargs),
|
|
87
|
+
'identify_pain_points': self.get_prompt('data_preparation', 'identify_pain_points', variables, **kwargs),
|
|
88
|
+
'financial_analysis': self.get_prompt('data_preparation', 'financial_analysis', variables, **kwargs),
|
|
89
|
+
'development_plans': self.get_prompt('data_preparation', 'development_plans', variables, **kwargs),
|
|
90
|
+
'technology_analysis': self.get_prompt('data_preparation', 'technology_analysis', variables, **kwargs)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
def get_lead_scoring_prompts(self, variables: Dict[str, Any], **kwargs) -> Dict[str, str]:
|
|
94
|
+
"""Get all prompts for lead scoring stage."""
|
|
95
|
+
return {
|
|
96
|
+
'evaluate_fit': self.get_prompt('lead_scoring', 'evaluate_fit', variables, **kwargs),
|
|
97
|
+
'score_calculation': self.get_prompt('lead_scoring', 'score_calculation', variables, **kwargs),
|
|
98
|
+
'competitive_analysis': self.get_prompt('lead_scoring', 'competitive_analysis', variables, **kwargs),
|
|
99
|
+
'recommendation': self.get_prompt('lead_scoring', 'recommendation', variables, **kwargs)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def get_initial_outreach_prompts(self, variables: Dict[str, Any], **kwargs) -> Dict[str, str]:
|
|
103
|
+
"""Get all prompts for initial outreach stage."""
|
|
104
|
+
return {
|
|
105
|
+
'email_generation': self.get_prompt('initial_outreach', 'email_generation', variables, **kwargs),
|
|
106
|
+
'subject_line': self.get_prompt('initial_outreach', 'subject_line', variables, **kwargs),
|
|
107
|
+
'tone_adjustment': self.get_prompt('initial_outreach', 'tone_adjustment', variables, **kwargs),
|
|
108
|
+
'personalization': self.get_prompt('initial_outreach', 'personalization', variables, **kwargs)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
def get_follow_up_prompts(self, variables: Dict[str, Any], **kwargs) -> Dict[str, str]:
|
|
112
|
+
"""Get all prompts for follow-up stage."""
|
|
113
|
+
return {
|
|
114
|
+
'analyze_interaction': self.get_prompt('follow_up', 'analyze_interaction', variables, **kwargs),
|
|
115
|
+
'generate_followup': self.get_prompt('follow_up', 'generate_followup', variables, **kwargs),
|
|
116
|
+
'timing_analysis': self.get_prompt('follow_up', 'timing_analysis', variables, **kwargs),
|
|
117
|
+
'sequence_planning': self.get_prompt('follow_up', 'sequence_planning', variables, **kwargs)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
def _substitute_variables(self, template: str, variables: Dict[str, Any]) -> str:
|
|
121
|
+
"""
|
|
122
|
+
Substitute variables in prompt template.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
template: Prompt template with placeholders
|
|
126
|
+
variables: Variables to substitute
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Template with variables substituted
|
|
130
|
+
"""
|
|
131
|
+
try:
|
|
132
|
+
# Handle nested dictionary access (e.g., {customer.name})
|
|
133
|
+
def replace_nested(match):
|
|
134
|
+
var_path = match.group(1)
|
|
135
|
+
value = self._get_nested_value(variables, var_path)
|
|
136
|
+
return str(value) if value is not None else f"{{{var_path}}}"
|
|
137
|
+
|
|
138
|
+
# Replace {variable} and {nested.variable} patterns
|
|
139
|
+
result = re.sub(r'\{([^}]+)\}', replace_nested, template)
|
|
140
|
+
|
|
141
|
+
return result
|
|
142
|
+
|
|
143
|
+
except Exception as e:
|
|
144
|
+
self.logger.warning(f"Variable substitution failed: {str(e)}")
|
|
145
|
+
return template
|
|
146
|
+
|
|
147
|
+
def _get_nested_value(self, data: Dict[str, Any], path: str) -> Any:
|
|
148
|
+
"""
|
|
149
|
+
Get value from nested dictionary using dot notation.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
data: Dictionary to search
|
|
153
|
+
path: Dot-separated path (e.g., 'customer.name')
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Value at path or None if not found
|
|
157
|
+
"""
|
|
158
|
+
try:
|
|
159
|
+
keys = path.split('.')
|
|
160
|
+
value = data
|
|
161
|
+
|
|
162
|
+
for key in keys:
|
|
163
|
+
if isinstance(value, dict) and key in value:
|
|
164
|
+
value = value[key]
|
|
165
|
+
else:
|
|
166
|
+
return None
|
|
167
|
+
|
|
168
|
+
return value
|
|
169
|
+
|
|
170
|
+
except Exception:
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
def validate_prompt_variables(self, template: str, variables: Dict[str, Any]) -> Dict[str, Any]:
|
|
174
|
+
"""
|
|
175
|
+
Validate that all required variables are provided for a template.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
template: Prompt template
|
|
179
|
+
variables: Available variables
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Dictionary with validation results
|
|
183
|
+
"""
|
|
184
|
+
# Find all variable placeholders
|
|
185
|
+
placeholders = re.findall(r'\{([^}]+)\}', template)
|
|
186
|
+
|
|
187
|
+
missing_vars = []
|
|
188
|
+
available_vars = []
|
|
189
|
+
|
|
190
|
+
for placeholder in placeholders:
|
|
191
|
+
value = self._get_nested_value(variables, placeholder)
|
|
192
|
+
if value is None:
|
|
193
|
+
missing_vars.append(placeholder)
|
|
194
|
+
else:
|
|
195
|
+
available_vars.append(placeholder)
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
'valid': len(missing_vars) == 0,
|
|
199
|
+
'missing_variables': missing_vars,
|
|
200
|
+
'available_variables': available_vars,
|
|
201
|
+
'total_placeholders': len(placeholders)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
def create_variable_context(self,
|
|
205
|
+
customer_data: Optional[Dict[str, Any]] = None,
|
|
206
|
+
lead_scores: Optional[Dict[str, Any]] = None,
|
|
207
|
+
org_info: Optional[Dict[str, Any]] = None,
|
|
208
|
+
team_info: Optional[Dict[str, Any]] = None,
|
|
209
|
+
**additional_vars) -> Dict[str, Any]:
|
|
210
|
+
"""
|
|
211
|
+
Create a comprehensive variable context for prompt substitution.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
customer_data: Customer information
|
|
215
|
+
lead_scores: Lead scoring results
|
|
216
|
+
org_info: Organization information
|
|
217
|
+
team_info: Team information
|
|
218
|
+
**additional_vars: Additional variables
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
Complete variable context
|
|
222
|
+
"""
|
|
223
|
+
context = {}
|
|
224
|
+
|
|
225
|
+
if customer_data:
|
|
226
|
+
context['customer'] = customer_data
|
|
227
|
+
context['company'] = customer_data.get('companyInfo', {})
|
|
228
|
+
context['contact'] = customer_data.get('primaryContact', {})
|
|
229
|
+
context['pain_points'] = customer_data.get('painPoints', [])
|
|
230
|
+
|
|
231
|
+
if lead_scores:
|
|
232
|
+
context['lead_scores'] = lead_scores
|
|
233
|
+
context['top_score'] = max(lead_scores.get('scores', []), key=lambda x: x.get('score', 0), default={})
|
|
234
|
+
|
|
235
|
+
if org_info:
|
|
236
|
+
context['org'] = org_info
|
|
237
|
+
context['seller'] = org_info
|
|
238
|
+
|
|
239
|
+
if team_info:
|
|
240
|
+
context['team'] = team_info
|
|
241
|
+
|
|
242
|
+
# Add additional variables
|
|
243
|
+
context.update(additional_vars)
|
|
244
|
+
|
|
245
|
+
return context
|