feat(intelligence): add competitor watch system
- Weekly automated scraping of 10 competitors - Structured data storage (competitors.json) - Validation and alerting scripts - First weekly report (2026-07-11) with 4 critical findings: 1. Premise Data acquired by Culmen (Aug 2025) 2. Streetbees bankruptcy (Aug 2025) 3. Moody's/Cape Analytics integration progressing 4. Sweden Platform Work Act proposed (Dec 2026) - Cron scheduled for Saturdays 07:00 UTC
This commit is contained in:
+142
@@ -0,0 +1,142 @@
|
||||
#!/bin/bash
|
||||
# Valideringsskript för konkurrensdata
|
||||
# Kontrollerar att all data är komplett och konsekvent
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
WORKSPACE="/home/bernt/.openclaw/workspace"
|
||||
WATCH_DIR="$WORKSPACE/intelligence/competitor-watch"
|
||||
DATA_DIR="$WATCH_DIR/data"
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
|
||||
ERRORS=0
|
||||
WARNINGS=0
|
||||
|
||||
echo "=== Validering av konkurrensdata — $DATE ==="
|
||||
echo ""
|
||||
|
||||
# 1. Kontrollera att competitors.json finns och är giltig JSON
|
||||
echo "--- 1. Kontrollerar competitors.json ---"
|
||||
if [ ! -f "$DATA_DIR/competitors.json" ]; then
|
||||
echo " ❌ ERROR: competitors.json saknas"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
else
|
||||
if python3 -c "import json; json.load(open('$DATA_DIR/competitors.json'))" 2>/dev/null; then
|
||||
echo " ✅ competitors.json är giltig JSON"
|
||||
|
||||
# Kontrollera antal konkurrenter
|
||||
COUNT=$(python3 -c "import json; d=json.load(open('$DATA_DIR/competitors.json')); print(len(d['competitors']))")
|
||||
echo " 📊 Antal konkurrenter: $COUNT"
|
||||
|
||||
if [ "$COUNT" -lt 10 ]; then
|
||||
echo " ⚠️ WARNING: Färre än 10 konkurrenter ($COUNT)"
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
fi
|
||||
else
|
||||
echo " ❌ ERROR: competitors.json är ogiltig JSON"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 2. Kontrollera att alla konkurrenter har nödvändiga fält
|
||||
echo "--- 2. Kontrollerar obligatoriska fält ---"
|
||||
REQUIRED_FIELDS=("rank" "name" "segment" "priority" "status" "threat_level")
|
||||
|
||||
for field in "${REQUIRED_FIELDS[@]}"; do
|
||||
MISSING=$(python3 -c "
|
||||
import json
|
||||
d=json.load(open('$DATA_DIR/competitors.json'))
|
||||
missing = [c['name'] for c in d['competitors'] if '$field' not in c or not c['$field']]
|
||||
print('\n'.join(missing)) if missing else print('OK')
|
||||
" 2>/dev/null)
|
||||
|
||||
if [ "$MISSING" = "OK" ]; then
|
||||
echo " ✅ $field: alla konkurrenter har värdet"
|
||||
else
|
||||
echo " ⚠️ WARNING: $field saknas för:"
|
||||
echo "$MISSING" | sed 's/^/ - /'
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
# 3. Kontrollera att prisdata är aktuell
|
||||
echo "--- 3. Kontrollerar prisdata ---"
|
||||
STALE_PRICES=$(python3 -c "
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
d=json.load(open('$DATA_DIR/competitors.json'))
|
||||
stale = []
|
||||
for c in d['competitors']:
|
||||
if 'pricing' in c and 'last_verified' in c['pricing']:
|
||||
lv = c['pricing']['last_verified']
|
||||
if lv:
|
||||
date = datetime.strptime(lv, '%Y-%m-%d')
|
||||
if datetime.now() - date > timedelta(days=90):
|
||||
stale.append(f\"{c['name']} (senast: {lv})\")
|
||||
print('\n'.join(stale)) if stale else print('OK')
|
||||
" 2>/dev/null)
|
||||
|
||||
if [ "$STALE_PRICES" = "OK" ]; then
|
||||
echo " ✅ All prisdata är aktuell (< 90 dagar)"
|
||||
else
|
||||
echo " ⚠️ WARNING: Föråldrade priser:"
|
||||
echo "$STALE_PRICES" | sed 's/^/ - /'
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 4. Kontrollera att senaste rapporten finns
|
||||
echo "--- 4. Kontrollerar rapporter ---"
|
||||
LATEST_REPORT=$(find "$WATCH_DIR/reports" -name "*-weekly-report.md" | sort | tail -1)
|
||||
if [ -n "$LATEST_REPORT" ]; then
|
||||
REPORT_DATE=$(basename "$LATEST_REPORT" | cut -d'-' -f1-3)
|
||||
echo " ✅ Senaste rapport: $REPORT_DATE"
|
||||
|
||||
# Kontrollera om rapporten är äldre än 8 dagar
|
||||
REPORT_AGE=$(( ($(date +%s) - $(date -d "$REPORT_DATE" +%s)) / 86400 ))
|
||||
if [ "$REPORT_AGE" -gt 8 ]; then
|
||||
echo " ⚠️ WARNING: Rapporten är $REPORT_AGE dagar gammal"
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ WARNING: Ingen rapport hittad"
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 5. Kontrollera att skrapade filer finns
|
||||
echo "--- 5. Kontrollerar skrapade data ---"
|
||||
LATEST_SIGNALS=$(find "$DATA_DIR/signals" -maxdepth 1 -type d -name "2026-*" | sort | tail -1)
|
||||
if [ -n "$LATEST_SIGNALS" ]; then
|
||||
SIGNAL_COUNT=$(find "$LATEST_SIGNALS" -type f | wc -l)
|
||||
echo " ✅ Senaste skrapning: $(basename $LATEST_SIGNALS) ($SIGNAL_COUNT filer)"
|
||||
|
||||
SIGNAL_AGE=$(( ($(date +%s) - $(date -d "$(basename $LATEST_SIGNALS)" +%s)) / 86400 ))
|
||||
if [ "$SIGNAL_AGE" -gt 8 ]; then
|
||||
echo " ⚠️ WARNING: Skrapningen är $SIGNAL_AGE dagar gammal"
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ WARNING: Inga skrapade signaler hittade"
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Sammanfattning
|
||||
echo "=== Validering slutförd ==="
|
||||
echo "Errors: $ERRORS"
|
||||
echo "Warnings: $WARNINGS"
|
||||
echo ""
|
||||
|
||||
if [ "$ERRORS" -gt 0 ]; then
|
||||
echo "❌ VALIDERING MISSLYCKADES — åtgärda errors"
|
||||
exit 1
|
||||
elif [ "$WARNINGS" -gt 0 ]; then
|
||||
echo "⚠️ VALIDERING GODKÄND med varningar"
|
||||
exit 0
|
||||
else
|
||||
echo "✅ VALIDERING GODKÄND"
|
||||
exit 0
|
||||
fi
|
||||
Reference in New Issue
Block a user