feat: Enhanced Outreach UI - Top 5 default + specific role generation
- market_intel_orchestrator.py: Updated generate_outreach_campaign to identify all relevant roles, generate top 5, and return remaining as suggestions. Added specific_role mode. - types.ts: Added OutreachResponse interface. - geminiService.ts: Updated to handle new response structure and specificRole parameter. - StepOutreach.tsx: Added sidebar section for Suggested Roles with on-demand generation buttons.
This commit is contained in:
@@ -544,25 +544,64 @@ def analyze_company(company_name, strategy, target_market):
|
||||
"dataSource": "Error"
|
||||
}
|
||||
|
||||
def generate_outreach_campaign(company_data_json, knowledge_base_content, reference_url):
|
||||
def generate_outreach_campaign(company_data_json, knowledge_base_content, reference_url, specific_role=None):
|
||||
"""
|
||||
Erstellt personalisierte E-Mail-Kampagnen basierend auf Audit-Daten und einer strukturierten Wissensdatenbank.
|
||||
Generiert spezifische Ansprachen für verschiedene Rollen (Personas).
|
||||
Erstellt personalisierte E-Mail-Kampagnen.
|
||||
Modus A (Default): Generiert Top 5 Kampagnen + Liste weiterer relevanter Rollen.
|
||||
Modus B (specific_role): Generiert nur Kampagne für diese eine Rolle.
|
||||
"""
|
||||
company_name = company_data_json.get('companyName', 'Unknown')
|
||||
logger.info(f"--- STARTING ROLE-BASED OUTREACH GENERATION FOR: {company_name} ---")
|
||||
logger.info(f"--- STARTING OUTREACH GENERATION FOR: {company_name} (Role: {specific_role if specific_role else 'Top 5'}) ---")
|
||||
|
||||
api_key = load_gemini_api_key()
|
||||
# Switch to stable 2.5-pro model
|
||||
GEMINI_API_URL = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent?key={api_key}"
|
||||
|
||||
if specific_role:
|
||||
# --- MODE B: SINGLE ROLE GENERATION ---
|
||||
task_description = f"""
|
||||
--- TASK ---
|
||||
1. **Focus**: Create a highly specific 3-step email campaign ONLY for the role: '{specific_role}'.
|
||||
2. **Analyze**: Use the Audit Facts to find specific hooks for this role.
|
||||
3. **Draft**: Write the sequence (Opening, Follow-up, Break-up).
|
||||
"""
|
||||
output_format = """
|
||||
--- OUTPUT FORMAT (Strictly JSON) ---
|
||||
{
|
||||
"target_role": "The requested role",
|
||||
"rationale": "Why this fits...",
|
||||
"emails": [ ... ]
|
||||
}
|
||||
"""
|
||||
else:
|
||||
# --- MODE A: INITIAL BATCH (TOP 5 + SUGGESTIONS) ---
|
||||
task_description = f"""
|
||||
--- TASK ---
|
||||
1. **Analyze**: Match the Target Company (Input 2) to the most relevant 'Zielbranche/Segment' from the Knowledge Base (Input 1).
|
||||
2. **Identify Roles**: Identify ALL relevant 'Rollen' (Personas) from the Knowledge Base that fit this company.
|
||||
3. **Select Top 5**: Choose the 5 most promising roles for immediate outreach based on the Audit findings.
|
||||
4. **Draft Campaigns**: For EACH of the Top 5 roles, write a 3-step email sequence.
|
||||
5. **List Others**: List the names of the other relevant roles that you identified but did NOT generate campaigns for yet.
|
||||
"""
|
||||
output_format = """
|
||||
--- OUTPUT FORMAT (Strictly JSON) ---
|
||||
{
|
||||
"campaigns": [
|
||||
{
|
||||
"target_role": "Role Name",
|
||||
"rationale": "Why selected...",
|
||||
"emails": [ ... ]
|
||||
},
|
||||
... (Top 5)
|
||||
],
|
||||
"available_roles": [ "Role 6", "Role 7", ... ]
|
||||
}
|
||||
"""
|
||||
|
||||
prompt = f"""
|
||||
You are a Strategic Key Account Manager and deeply technical Industry Insider.
|
||||
Your goal is to write highly personalized, **operationally specific** outreach emails to the company '{company_name}'.
|
||||
|
||||
--- INPUT 1: YOUR IDENTITY & STRATEGY (The Sender) ---
|
||||
The following Markdown contains your company's identity, products, and strategy.
|
||||
You act as the sales representative for the company described here:
|
||||
{knowledge_base_content}
|
||||
|
||||
--- INPUT 2: THE TARGET COMPANY (Audit Facts) ---
|
||||
@@ -571,52 +610,21 @@ def generate_outreach_campaign(company_data_json, knowledge_base_content, refere
|
||||
--- INPUT 3: THE REFERENCE CLIENT (Social Proof) ---
|
||||
Reference Client URL: {reference_url}
|
||||
|
||||
CRITICAL: This 'Reference Client' is an existing happy customer of ours. They are the "Seed Company" used to find the Target Company (Lookalike).
|
||||
You MUST mention this Reference Client by name (derive it from the URL, e.g., 'schindler.com' -> 'Schindler') to establish trust.
|
||||
CRITICAL: This 'Reference Client' is an existing happy customer of ours. You MUST mention them by name to establish trust.
|
||||
|
||||
--- TASK ---
|
||||
1. **Analyze**: Match the Target Company (Input 2) to the most relevant 'Zielbranche/Segment' from the Knowledge Base (Input 1).
|
||||
2. **Select Roles**: Identify **up to 5** of the most distinct and relevant 'Rollen' (Personas) from the Knowledge Base for this specific company situation.
|
||||
- Prioritize roles where the audit findings (e.g., specific competitor tech, growth pains) offer the strongest hook.
|
||||
- *Example:* If the audit says they use a competitor (risk of lock-in), select a role like "Strategic Purchaser" or "Head of R&D".
|
||||
3. **Draft Campaigns**: For **EACH** of the selected roles, write a 3-step email sequence.
|
||||
{task_description}
|
||||
|
||||
--- TONE & STYLE GUIDELINES (CRITICAL) ---
|
||||
- **Perspective:** Operational Expert & Insider. NOT generic marketing.
|
||||
- **Be Gritty & Specific:** Do NOT use fluff like "optimize efficiency" or "streamline processes" without context.
|
||||
- Use **hard, operational keywords** from the Knowledge Base (e.g., "ASNs", "VMI", "8D-Reports", "Maverick Buying", "Bandstillstand", "Sonderfahrten", "PPAP").
|
||||
- Show you understand their daily pain.
|
||||
- **Be Gritty & Specific:** Use hard, operational keywords from the Knowledge Base (e.g., "ASNs", "8D-Reports").
|
||||
- **Narrative Arc:**
|
||||
1. "I noticed [Fact from Audit/Tech Stack]..." (e.g., "You rely on PDF orders via Jaggaer...")
|
||||
2. "In [Industry], this often leads to [Operational Pain]..." (e.g., "missing ASNs causing delays at the hub.")
|
||||
3. "We helped [Reference Client Name] solve exactly this by [Specific Solution]..."
|
||||
4. "Let's discuss how to get [Operational Gain] without replacing your ERP."
|
||||
- **Mandatory Social Proof:** You MUST mention the Reference Client Name (from Input 3) in the email body or footer.
|
||||
- **Language:** German (as the inputs are German).
|
||||
1. "I noticed [Fact from Audit]..."
|
||||
2. "In [Industry], this often leads to [Pain]..."
|
||||
3. "We helped [Reference Client] solve this..."
|
||||
4. "Let's discuss [Gain]."
|
||||
- **Language:** German.
|
||||
|
||||
--- OUTPUT FORMAT (Strictly JSON) ---
|
||||
Returns a list of campaigns.
|
||||
[
|
||||
{{
|
||||
"target_role": "Name of the Role (e.g. Leiter F&E)",
|
||||
"rationale": "Why this role? (e.g. Because the audit found dependency on Competitor X...)",
|
||||
"emails": [
|
||||
{{
|
||||
"subject": "Specific Subject Line",
|
||||
"body": "Email Body..."
|
||||
}},
|
||||
{{
|
||||
"subject": "Re: Subject",
|
||||
"body": "Follow-up Body..."
|
||||
}},
|
||||
{{
|
||||
"subject": "Final Check",
|
||||
"body": "Final Body..."
|
||||
}}
|
||||
]
|
||||
}},
|
||||
... (Second Role)
|
||||
]
|
||||
{output_format}
|
||||
"""
|
||||
|
||||
payload = {
|
||||
@@ -626,12 +634,10 @@ def generate_outreach_campaign(company_data_json, knowledge_base_content, refere
|
||||
|
||||
try:
|
||||
logger.info("Sende Campaign-Anfrage an Gemini API...")
|
||||
# logger.debug(f"Rohe Gemini API-Anfrage (JSON): {json.dumps(payload, indent=2)}")
|
||||
response = requests.post(GEMINI_API_URL, json=payload, headers={'Content-Type': 'application/json'})
|
||||
response.raise_for_status()
|
||||
response_data = response.json()
|
||||
logger.info(f"Gemini API-Antwort erhalten (Status: {response.status_code}).")
|
||||
# logger.debug(f"Rohe API-Antwort (JSON): {json.dumps(response_data, indent=2)}")
|
||||
|
||||
text = response_data['candidates'][0]['content']['parts'][0]['text']
|
||||
result = _extract_json_from_text(text)
|
||||
@@ -642,7 +648,7 @@ def generate_outreach_campaign(company_data_json, knowledge_base_content, refere
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"Campaign generation failed for {company_name}: {e}")
|
||||
return [{"error": str(e)}]
|
||||
return {"error": str(e)}
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -653,7 +659,8 @@ def main():
|
||||
parser.add_argument("--company_name")
|
||||
parser.add_argument("--strategy_json")
|
||||
parser.add_argument("--summary_of_offer")
|
||||
parser.add_argument("--company_data_file") # For generate_outreach
|
||||
parser.add_argument("--company_data_file")
|
||||
parser.add_argument("--specific_role") # New argument
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.mode == "generate_strategy":
|
||||
@@ -671,7 +678,7 @@ def main():
|
||||
elif args.mode == "generate_outreach":
|
||||
with open(args.company_data_file, "r") as f: company_data = json.load(f)
|
||||
with open(args.context_file, "r") as f: knowledge_base = f.read()
|
||||
print(json.dumps(generate_outreach_campaign(company_data, knowledge_base, args.reference_url)))
|
||||
print(json.dumps(generate_outreach_campaign(company_data, knowledge_base, args.reference_url, args.specific_role)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user