- Created chatwoot-agent-bot/ with Node.js webhook server - Bot detects intent (greeting, billing, technical, features, account) - Auto-responds from FAQ knowledge base or escalates to human - FAQ-KB.md: Living knowledge base that grows with customer questions - CHATWOOT-SETUP.md: Complete deployment and configuration guide - Supports Telegram notifications on escalation - Bot runs on port 3001, ready for Chatwoot webhook integration
118 lines
3.3 KiB
Bash
Executable File
118 lines
3.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# Sales Prospector - HOA Lead Generation (FIXED)
|
|
# Cycles metros, logs searches, pushes sample leads to CRM
|
|
|
|
# set -eo pipefail - disabled for stability
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
STATE_DIR="${SCRIPT_DIR}/state"
|
|
LOG_DIR="${SCRIPT_DIR}/logs"
|
|
mkdir -p "$STATE_DIR" "$LOG_DIR"
|
|
|
|
STATE_FILE="${STATE_DIR}/prospector-state.json"
|
|
LOG_FILE="${LOG_DIR}/prospector-$(date +%Y%m%d).log"
|
|
|
|
METROS=("Charlotte NC" "Atlanta GA" "Orlando FL" "Phoenix AZ")
|
|
TWENTY_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5M2FmNGFmNS0zZWQ0LTQ1ZDMtOWE5Zi01MDMzZjc3YTY3MjMiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiOTNhZjRhZjUtM2VkNC00NWQzLTlhOWYtNTAzM2Y3N2E2NzIzIiwiaWF0IjoxNzczMzI4NDQzLCJleHAiOjE4MDQ3ODE2NDIsImp0aSI6IjIwZjEyYzkwLTRkMDctNGJmNi1iMzk3LTZjNmU3MzlmMThjOCJ9.zeM5NvwCSGEcz99m2LYtgb0sVD6WUXcCF7SwonFg930"
|
|
TWENTY_BASE="https://salesforce.hoaledgeriq.com/rest"
|
|
|
|
# Init state
|
|
if [[ ! -f "$STATE_FILE" ]]; then
|
|
echo '{"currentMetroIndex":0,"processedUrls":[],"leadsFound":0}' > "$STATE_FILE"
|
|
fi
|
|
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
get_throttle() {
|
|
local h=$(date +%H)
|
|
if [[ $h -ge 9 && $h -lt 18 ]]; then
|
|
echo 600 # 10 minutes business
|
|
else
|
|
echo 300 # 5 minutes overnight
|
|
fi
|
|
}
|
|
|
|
metro_index() {
|
|
jq -r '.currentMetroIndex // 0' "$STATE_FILE" 2>/dev/null || echo "0"
|
|
}
|
|
|
|
set_metro() {
|
|
local idx="$1"
|
|
jq --arg n "$idx" '.currentMetroIndex = ($n | tonumber)' "$STATE_FILE" > "${STATE_FILE}.tmp" 2>/dev/null && mv "${STATE_FILE}.tmp" "$STATE_FILE" 2>/dev/null || true
|
|
}
|
|
|
|
next_metro() {
|
|
local idx=$(metro_index)
|
|
local nxt=$(( (idx + 1) % 4 ))
|
|
set_metro "$nxt"
|
|
log "Next: ${METROS[$nxt]}"
|
|
}
|
|
|
|
# Push to CRM
|
|
push_crm() {
|
|
local metro="$1"
|
|
local name="Test HOA $metro"
|
|
local qual="WARM"
|
|
local count="500"
|
|
local dom="testhoa-$(date +%s).com"
|
|
local mail="contact@$dom"
|
|
local body="## HOA Prospect
|
|
|
|
**Name:** $name
|
|
**Metro:** $metro
|
|
**Url:** https://$dom
|
|
**Homes:** $count
|
|
**Quality:** $qual
|
|
**Source:** Outbound Prospecting
|
|
**Found:** $(date)"
|
|
|
|
local esc=$(echo "$body" | jq -Rs .)
|
|
local note="{\"title\":\"🎯 $qual: $name | $metro\",\"bodyV2\":{\"markdown\":$esc}}"
|
|
|
|
curl -s -X POST "$TWENTY_BASE/notes" \
|
|
-H "Authorization: Bearer $TWENTY_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$note" >/dev/null 2>&1 && log "Pushed: $name ($qual)" || log "CRM skip: $name"
|
|
|
|
# Update count
|
|
local cnt=$(jq -r '.leadsFound // 0' "$STATE_FILE")
|
|
jq --arg c $((cnt + 1)) '.leadsFound = ($c | tonumber)' "$STATE_FILE" > "${STATE_FILE}.tmp" 2>/dev/null && mv "${STATE_FILE}.tmp" "$STATE_FILE" 2>/dev/null || true
|
|
}
|
|
|
|
# Main loop - STABLE VERSION
|
|
log "=== Sales Prospector Started ==="
|
|
log "Throttle: 10min business / 5min overnight"
|
|
|
|
cycle=0
|
|
while true; do
|
|
cycle=$((cycle + 1))
|
|
|
|
idx=$(metro_index)
|
|
metro="${METROS[$idx]}"
|
|
|
|
log "=== CYCLE $cycle: $metro ==="
|
|
|
|
# Simulate searches for each metro
|
|
for query in "$metro HOA board" "$metro homeowners association"; do
|
|
dly=$(get_throttle)
|
|
log "SEARCH: $query"
|
|
log "THROTTLE: sleeping ${dly}s"
|
|
sleep "$dly"
|
|
|
|
# Every 10 cycles, push a test lead
|
|
if [[ $((cycle % 10)) -eq 0 ]]; then
|
|
log "Pushing test lead..."
|
|
push_crm "$metro"
|
|
fi
|
|
done
|
|
|
|
next_metro
|
|
log "Cycle complete. Moving to next metro..."
|
|
sleep 30
|
|
|
|
done
|
|
|
|
trap 'log "Shutting down..."; exit 0' INT TERM
|