Spaces:
Sleeping
Sleeping
Integrate lead_scoring_agent: score leads at start, inject scoring fields into asset flow
Browse files- recovery_enrichment_agent.py +22 -11
recovery_enrichment_agent.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
| 1 |
"""
|
| 2 |
Recovery/Enrichment Agent
|
| 3 |
-
|
| 4 |
Implements prioritized enrichment source config, rate limiting, retry/backoff, queue/handoff, and full action/decision logging for leads enrichment and recovery workflows.
|
|
|
|
| 5 |
"""
|
| 6 |
-
|
| 7 |
import time
|
| 8 |
import logging
|
| 9 |
from enum import Enum
|
| 10 |
from typing import List, Dict, Any, Optional
|
|
|
|
| 11 |
|
| 12 |
# Agent config
|
| 13 |
class EnrichmentSource(Enum):
|
|
@@ -34,22 +34,32 @@ class LeadBatchHandler:
|
|
| 34 |
self.history = []
|
| 35 |
self.rate_limit_counter = 0
|
| 36 |
self.last_reset = time.time()
|
| 37 |
-
|
| 38 |
def reset_rate_limit(self):
|
| 39 |
now = time.time()
|
| 40 |
if now - self.last_reset > 60:
|
| 41 |
self.rate_limit_counter = 0
|
| 42 |
self.last_reset = now
|
| 43 |
log_event("rate_limit_reset", {})
|
| 44 |
-
|
| 45 |
def handle_lead_batch(self, leads: List[Dict[str, Any]]):
|
| 46 |
results = []
|
| 47 |
for lead in leads:
|
| 48 |
result = self._process_lead(lead)
|
| 49 |
results.append(result)
|
| 50 |
return results
|
| 51 |
-
|
| 52 |
def _process_lead(self, lead: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
self.reset_rate_limit()
|
| 54 |
for source in self.config["priority_sources"]:
|
| 55 |
for attempt in range(self.config["max_retries"]):
|
|
@@ -64,13 +74,14 @@ class LeadBatchHandler:
|
|
| 64 |
success, data = self._enrich_from_source(source, lead)
|
| 65 |
if success:
|
| 66 |
log_event("enrich_success", {"source": source.value, "lead": lead})
|
| 67 |
-
|
|
|
|
| 68 |
else:
|
| 69 |
log_event("enrich_failure", {"source": source.value, "lead": lead, "attempt": attempt+1})
|
| 70 |
time.sleep(self.config["retry_backoff_seconds"])
|
| 71 |
self._escalate_to_human(lead)
|
| 72 |
-
return {"lead": lead, "enriched": None, "escalated": True}
|
| 73 |
-
|
| 74 |
def _enrich_from_source(self, source: EnrichmentSource, lead: Dict[str, Any]) -> (bool, Optional[dict]):
|
| 75 |
# Simulation logic; replace with real API/browser/human integration
|
| 76 |
if source == EnrichmentSource.API:
|
|
@@ -80,11 +91,11 @@ class LeadBatchHandler:
|
|
| 80 |
if source == EnrichmentSource.HUMAN_REVIEW:
|
| 81 |
return True, {"company": "Simulated Corp", "status": "Human reviewed"}
|
| 82 |
return False, None
|
| 83 |
-
|
| 84 |
def _escalate_to_human(self, lead: Dict[str, Any]):
|
| 85 |
self.queue.append(lead)
|
| 86 |
log_event("escalate", {"lead": lead})
|
| 87 |
-
|
| 88 |
def get_audit_log(self):
|
| 89 |
# Return all logged history (simulate)
|
| 90 |
pass
|
|
@@ -102,4 +113,4 @@ def simulate_lead_handoff():
|
|
| 102 |
# add more logic for audit/fallback/escalation as needed
|
| 103 |
|
| 104 |
if __name__ == "__main__":
|
| 105 |
-
simulate_lead_handoff()
|
|
|
|
| 1 |
"""
|
| 2 |
Recovery/Enrichment Agent
|
|
|
|
| 3 |
Implements prioritized enrichment source config, rate limiting, retry/backoff, queue/handoff, and full action/decision logging for leads enrichment and recovery workflows.
|
| 4 |
+
Integrates lead_scoring_agent to score leads at the start of processing and inject scoring fields into the asset flow for analytics and UI visibility.
|
| 5 |
"""
|
|
|
|
| 6 |
import time
|
| 7 |
import logging
|
| 8 |
from enum import Enum
|
| 9 |
from typing import List, Dict, Any, Optional
|
| 10 |
+
from lead_scoring_agent import score_lead
|
| 11 |
|
| 12 |
# Agent config
|
| 13 |
class EnrichmentSource(Enum):
|
|
|
|
| 34 |
self.history = []
|
| 35 |
self.rate_limit_counter = 0
|
| 36 |
self.last_reset = time.time()
|
| 37 |
+
|
| 38 |
def reset_rate_limit(self):
|
| 39 |
now = time.time()
|
| 40 |
if now - self.last_reset > 60:
|
| 41 |
self.rate_limit_counter = 0
|
| 42 |
self.last_reset = now
|
| 43 |
log_event("rate_limit_reset", {})
|
| 44 |
+
|
| 45 |
def handle_lead_batch(self, leads: List[Dict[str, Any]]):
|
| 46 |
results = []
|
| 47 |
for lead in leads:
|
| 48 |
result = self._process_lead(lead)
|
| 49 |
results.append(result)
|
| 50 |
return results
|
| 51 |
+
|
| 52 |
def _process_lead(self, lead: Dict[str, Any]) -> Dict[str, Any]:
|
| 53 |
+
# Score the lead at the start of processing and inject scoring fields
|
| 54 |
+
scoring_data = score_lead(lead)
|
| 55 |
+
lead.update({
|
| 56 |
+
"lead_score": scoring_data.get("score", 0),
|
| 57 |
+
"score_tier": scoring_data.get("tier", "unknown"),
|
| 58 |
+
"score_factors": scoring_data.get("factors", {}),
|
| 59 |
+
"scored_at": time.time()
|
| 60 |
+
})
|
| 61 |
+
log_event("lead_scored", {"lead": lead, "scoring": scoring_data})
|
| 62 |
+
|
| 63 |
self.reset_rate_limit()
|
| 64 |
for source in self.config["priority_sources"]:
|
| 65 |
for attempt in range(self.config["max_retries"]):
|
|
|
|
| 74 |
success, data = self._enrich_from_source(source, lead)
|
| 75 |
if success:
|
| 76 |
log_event("enrich_success", {"source": source.value, "lead": lead})
|
| 77 |
+
# Preserve scoring fields in enriched result
|
| 78 |
+
return {"lead": lead, "enriched": data, "lead_score": lead["lead_score"], "score_tier": lead["score_tier"]}
|
| 79 |
else:
|
| 80 |
log_event("enrich_failure", {"source": source.value, "lead": lead, "attempt": attempt+1})
|
| 81 |
time.sleep(self.config["retry_backoff_seconds"])
|
| 82 |
self._escalate_to_human(lead)
|
| 83 |
+
return {"lead": lead, "enriched": None, "escalated": True, "lead_score": lead["lead_score"], "score_tier": lead["score_tier"]}
|
| 84 |
+
|
| 85 |
def _enrich_from_source(self, source: EnrichmentSource, lead: Dict[str, Any]) -> (bool, Optional[dict]):
|
| 86 |
# Simulation logic; replace with real API/browser/human integration
|
| 87 |
if source == EnrichmentSource.API:
|
|
|
|
| 91 |
if source == EnrichmentSource.HUMAN_REVIEW:
|
| 92 |
return True, {"company": "Simulated Corp", "status": "Human reviewed"}
|
| 93 |
return False, None
|
| 94 |
+
|
| 95 |
def _escalate_to_human(self, lead: Dict[str, Any]):
|
| 96 |
self.queue.append(lead)
|
| 97 |
log_event("escalate", {"lead": lead})
|
| 98 |
+
|
| 99 |
def get_audit_log(self):
|
| 100 |
# Return all logged history (simulate)
|
| 101 |
pass
|
|
|
|
| 113 |
# add more logic for audit/fallback/escalation as needed
|
| 114 |
|
| 115 |
if __name__ == "__main__":
|
| 116 |
+
simulate_lead_handoff()
|