feat: Add Chatwoot Agent Bot prototype and FAQ knowledge base

- 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
This commit is contained in:
2026-04-01 16:26:05 -04:00
parent 7ba19752de
commit 5319bcd30b
1074 changed files with 456376 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
#!/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