|
|
|
|
|
""" |
|
|
Contactor Agent - Discovers decision-makers at target companies |
|
|
Now uses web search to find real contacts instead of generating mock data |
|
|
""" |
|
|
from app.schema import Prospect, Contact |
|
|
from app.config import SKIP_WEB_SEARCH |
|
|
import logging |
|
|
from services.prospect_discovery import get_prospect_discovery_service |
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
class Contactor: |
|
|
""" |
|
|
Discovers and validates decision-maker contacts |
|
|
|
|
|
IMPROVED: Now uses web search to discover real decision-makers |
|
|
Falls back to plausible generated contacts when search doesn't find results |
|
|
""" |
|
|
|
|
|
def __init__(self, mcp_registry): |
|
|
self.mcp = mcp_registry |
|
|
self.store = mcp_registry.get_store_client() |
|
|
self.prospect_discovery = get_prospect_discovery_service() |
|
|
|
|
|
async def run(self, prospect: Prospect) -> Prospect: |
|
|
"""Discover decision-maker contacts""" |
|
|
|
|
|
logger.info(f"Contactor: Finding contacts for '{prospect.company.name}'") |
|
|
|
|
|
|
|
|
suppressed = await self.store.check_suppression( |
|
|
"domain", |
|
|
prospect.company.domain |
|
|
) |
|
|
|
|
|
if suppressed: |
|
|
logger.warning(f"Contactor: Domain suppressed: {prospect.company.domain}") |
|
|
prospect.status = "dropped" |
|
|
prospect.dropped_reason = f"Domain suppressed: {prospect.company.domain}" |
|
|
await self.store.save_prospect(prospect) |
|
|
return prospect |
|
|
|
|
|
|
|
|
seen_emails = set() |
|
|
try: |
|
|
existing = await self.store.list_contacts_by_domain(prospect.company.domain) |
|
|
for contact in existing: |
|
|
if hasattr(contact, 'email'): |
|
|
seen_emails.add(contact.email.lower()) |
|
|
except Exception as e: |
|
|
logger.error(f"Contactor: Error fetching existing contacts: {str(e)}") |
|
|
|
|
|
|
|
|
contacts = [] |
|
|
try: |
|
|
|
|
|
max_contacts = 2 if prospect.company.size < 100 else 3 |
|
|
|
|
|
discovered_contacts = await self.prospect_discovery.discover_contacts( |
|
|
company_name=prospect.company.name, |
|
|
domain=prospect.company.domain, |
|
|
company_size=prospect.company.size, |
|
|
max_contacts=max_contacts, |
|
|
skip_search=SKIP_WEB_SEARCH |
|
|
) |
|
|
|
|
|
|
|
|
for contact in discovered_contacts: |
|
|
email_lower = contact.email.lower() |
|
|
|
|
|
|
|
|
if email_lower in seen_emails: |
|
|
logger.info(f"Contactor: Skipping duplicate email: {contact.email}") |
|
|
continue |
|
|
|
|
|
|
|
|
email_suppressed = await self.store.check_suppression("email", contact.email) |
|
|
if email_suppressed: |
|
|
logger.warning(f"Contactor: Email suppressed: {contact.email}") |
|
|
continue |
|
|
|
|
|
|
|
|
contact.prospect_id = prospect.id |
|
|
|
|
|
|
|
|
await self.store.save_contact(contact) |
|
|
contacts.append(contact) |
|
|
seen_emails.add(email_lower) |
|
|
|
|
|
logger.info(f"Contactor: Added contact: {contact.name} ({contact.title})") |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Contactor: Error discovering contacts: {str(e)}") |
|
|
|
|
|
|
|
|
|
|
|
prospect.contacts = contacts |
|
|
prospect.status = "contacted" |
|
|
await self.store.save_prospect(prospect) |
|
|
|
|
|
logger.info(f"Contactor: Found {len(contacts)} contacts for '{prospect.company.name}'") |
|
|
|
|
|
return prospect |
|
|
|