GMB-Scraper/lib/pitch_generator.py

277 lines
11 KiB
Python
Raw Normal View History

"""
Apex Pitch Generator Module
============================
Generate personalized cold outreach pitches based on pain signals.
Focus: Lead Generation as highest-margin service.
"""
from .logger import get_logger
# Pitch templates by pain signal
PITCH_TEMPLATES = {
'missed_calls': {
'hook': "I noticed {count} recent reviews mentioning people couldn't reach {business} by phone",
'problem': "Every missed call is a potential customer going to your competitor",
'solution': "I help businesses like yours capture every lead with smart call routing and instant follow-up",
'proof': "My last client recovered $12K/month in lost leads within 30 days",
'cta': "Can I show you how in a quick 10-minute call?",
},
'no_website': {
'hook': "I noticed {business} doesn't have a website yet",
'problem': "In 2026, 87% of customers search online before choosing a local business",
'solution': "I build fast, mobile-friendly websites that actually generate leads (not just look pretty)",
'proof': "Average client sees 15-20 new inquiries per month within 60 days",
'cta': "Want to see some examples of sites I've built for {industry} businesses?",
},
'broken_website': {
'hook': "I checked {business}'s website and noticed {issue}",
'problem': "This is likely costing you customers right now — Google penalizes broken sites in search rankings",
'solution': "I can fix this in 48 hours and get you back in Google's good books",
'proof': "Fixed 23 sites this year with avg 40% traffic increase within 2 weeks",
'cta': "Want me to send you a quick video showing exactly what's broken?",
},
'low_rating': {
'hook': "I noticed {business} has a {rating}★ rating with some concerning recent reviews",
'problem': "Anything under 4 stars is actively pushing customers to competitors",
'solution': "I help businesses rebuild their online reputation and respond professionally to negative reviews",
'proof': "Took a Joondalup dentist from 3.2★ to 4.6★ in 90 days with zero fake reviews",
'cta': "Can I share the exact system I use?",
},
'recent_1star': {
'hook': "I saw {business} got {count} one-star reviews in the last month",
'problem': "Unaddressed negative reviews stay on Google forever and scare away new customers",
'solution': "I help business owners respond professionally and turn critics into advocates",
'proof': "One client recovered from 8 bad reviews to 4.8★ rating in 60 days",
'cta': "Want to see the response templates that actually work?",
},
'unclaimed_gmb': {
'hook': "I noticed {business}'s Google Business profile appears unclaimed",
'problem': "Unclaimed profiles can't be optimized, so you're missing out on free local search traffic",
'solution': "I can claim and optimize your profile in 24 hours — it's the easiest SEO win available",
'proof': "Optimized profiles typically see 30-50% more calls within 30 days",
'cta': "Want me to walk you through the process?",
},
'few_reviews': {
'hook': "I noticed {business} only has {count} reviews on Google",
'problem': "Businesses with fewer than 20 reviews are invisible to most customers",
'solution': "I run ethical review generation campaigns that get real customers to leave real reviews",
'proof': "One client went from 12 to 87 reviews in 90 days — all genuine",
'cta': "Want to see the system I use?",
},
'no_contact_form': {
'hook': "I noticed {business}'s website doesn't have a contact form",
'problem': "You're relying 100% on phone calls, which means you're missing 60% of leads who prefer to fill forms",
'solution': "I add smart contact forms that capture leads 24/7 and send instant SMS notifications",
'proof': "Added forms to 15 sites this quarter — average 22 new leads/month per site",
'cta': "Can I mock up what it would look like on your site?",
},
'slow_website': {
'hook': "I tested {business}'s website and it took {load_time} seconds to load",
'problem': "Google's threshold is 3 seconds — anything slower loses 40% of visitors instantly",
'solution': "I optimize websites to load in under 2 seconds without rebuilding them",
'proof': "Average optimization takes 4 hours and improves load time by 60%",
'cta': "Want me to send you a speed report with specific fixes?",
},
'not_mobile_friendly': {
'hook': "I checked {business}'s website on my phone and it's not mobile-friendly",
'problem': "78% of local searches happen on mobile — Google actually hides non-mobile sites from phone users",
'solution': "I make existing websites mobile-friendly without a full rebuild",
'proof': "Mobile optimization typically recovers 30-40% of lost mobile traffic",
'cta': "Want me to show you what your site looks like on a phone right now?",
},
}
# Service pricing (for context, not mentioned in pitch)
SERVICE_PRICING = {
'Lead Generation + Call Tracking': {'setup': '$1,500', 'monthly': '$500/mo'},
'Website Development': {'setup': '$1,500-$3,000', 'monthly': '$150/mo hosting'},
'Website Maintenance': {'setup': '$500', 'monthly': '$300/mo'},
'Reputation Management': {'setup': '$800', 'monthly': '$400/mo'},
'Review Response Service': {'setup': '$300', 'monthly': '$200/mo'},
'GMB Optimization': {'setup': '$500', 'monthly': '$150/mo'},
'Review Generation Campaign': {'setup': '$500', 'monthly': '$300/mo'},
'Lead Capture Optimization': {'setup': '$600', 'monthly': '$100/mo'},
'Website Performance': {'setup': '$400', 'monthly': '$0'},
'Mobile Optimization': {'setup': '$500', 'monthly': '$0'},
}
def generate_apex_pitch(lead, pain_data, channel='sms'):
"""
Generate a personalized apex pitch for a lead.
Args:
lead: Business data dictionary
pain_data: Pain detection results from detect_pain_signals()
channel: 'sms', 'email', 'call', or 'gumtree'
Returns:
Dictionary with pitch components
"""
logger = get_logger()
if not pain_data or not pain_data.get('signals'):
return None
# Get primary signal (highest pain)
signals = pain_data['signals']
primary_key = max(signals.keys(), key=lambda k: signals[k].get('signal_info', {}).get('weight', 0))
primary_signal = signals[primary_key]
# Get template
template = PITCH_TEMPLATES.get(primary_key)
if not template:
# Fallback to generic
template = {
'hook': f"I noticed {lead.get('name', 'your business')} has some opportunities to improve online presence",
'problem': "These issues are likely costing you customers every day",
'solution': "I help local businesses fix these problems and generate more leads",
'proof': "Working with Perth businesses for 5+ years",
'cta': "Can I show you how?",
}
# Build context
context = {
'business': lead.get('name', 'your business'),
'industry': lead.get('category', 'local'),
'rating': lead.get('rating', 0),
'count': primary_signal.get('count', 1),
'load_time': '',
'issue': '',
}
# Add website-specific context
if 'slow_website' in signals:
details = signals['slow_website'].get('details', {})
context['load_time'] = f"{details.get('load_time', 4)}"
if 'broken_website' in signals:
details = signals['broken_website'].get('details', {})
issues = details.get('issues', [])
context['issue'] = issues[0] if issues else "some technical issues"
# Fill template
try:
hook = template['hook'].format(**context)
problem = template['problem'].format(**context)
solution = template['solution'].format(**context)
proof = template['proof'].format(**context)
cta = template['cta'].format(**context)
except KeyError as e:
logger.warning(f"Missing context for pitch template: {e}")
hook = f"I've been looking at {lead.get('name', 'your business')} online"
problem = template['problem']
solution = template['solution']
proof = template['proof']
cta = template['cta']
# Format for channel
if channel == 'sms':
# Short, punchy, under 160 chars ideally (but up to 320 OK)
pitch = f"{hook}. {cta}"
if len(pitch) > 160:
pitch = f"{hook[:80]}... {cta}"
elif channel == 'email':
# Full pitch with all components
pitch = f"""Hi,
{hook}.
{problem}.
{solution}. {proof}.
{cta}
Cheers,
Zul
Darwisyah Digital Media
0405 022 460"""
elif channel == 'call':
# Conversational script
pitch = f"""OPENING:
"Hi, is this {lead.get('name', 'the business')}? This is Zul — I'm a local business owner in Perth. I'll be quick.
{hook}. Is that something you've noticed yourself?"
PROBE:
"How has that been affecting your business?"
PITCH:
"{solution}. {proof}."
CLOSE:
"{cta}"
OBJECTION HANDLING:
- "Not interested": "Totally understand. Can I send you a quick 2-minute video showing what I found? No pressure either way."
- "How much?": "Depends on what you need — happy to give you a ballpark if you tell me more about what's not working."
- "Send info": "Will do — what's the best email? And quick question — what's your biggest challenge right now with [problem area]?"
"""
elif channel == 'gumtree':
# Casual, local tone
pitch = f"""Hi there,
I came across {lead.get('name', 'your business')} online and noticed {hook.lower()}.
{problem}.
I'm Zul, a local Perth guy who helps businesses fix exactly these kinds of issues. {solution}. {proof}.
{cta}
Happy to chat no hard sell.
Cheers,
Zul
0405 022 460"""
else:
pitch = f"{hook}. {problem}. {solution}. {proof}. {cta}"
result = {
'pitch': pitch,
'channel': channel,
'primary_service': pain_data.get('primary_service'),
'pain_score': pain_data.get('pain_score'),
'hook': hook,
'problem': problem,
'solution': solution,
'proof': proof,
'cta': cta,
'pricing': SERVICE_PRICING.get(pain_data.get('primary_service'), {}),
}
logger.info(f"Generated {channel} pitch for '{lead.get('name')}': pain_score={pain_data.get('pain_score')}")
return result
def generate_batch_pitches(leads_with_pain, channel='sms'):
"""
Generate pitches for multiple leads.
Args:
leads_with_pain: List of (lead, pain_data) tuples
channel: Pitch channel
Returns:
List of pitch dictionaries
"""
pitches = []
for lead, pain_data in leads_with_pain:
if pain_data and pain_data.get('pain_score', 0) > 0:
pitch = generate_apex_pitch(lead, pain_data, channel)
if pitch:
pitches.append({
'lead': lead,
'pitch': pitch,
})
return pitches