import os import json import aiosqlite from app.db import SQLITE_PATH KNOWN_CMS = {"wordpress", "joomla", "drupal", "wix", "squarespace", "shopify", "prestashop", "magento", "typo3", "opencart"} TARGET_COUNTRIES = set(os.getenv("TARGET_COUNTRIES", "ES,GB,DE,FR,RO,PT,AD,IT").split(",")) LOCAL_BIZ_KEYWORDS = { "restaurant", "cafe", "shop", "store", "salon", "plumber", "electrician", "dentist", "clinic", "garage", "hotel", "bakery", "bar", "gym", "spa", "fontanero", "electricista", "dentista", "clínica", "taller", "panadería", "peluquería", "tienda", "abogado", "gestor", "inmobili", } def local_biz_keywords(title: str | None) -> bool: if not title: return False title_lower = title.lower() return any(kw in title_lower for kw in LOCAL_BIZ_KEYWORDS) def score(domain_row: dict) -> int: # Dead sites are unreachable — cap at 5 regardless of other signals if not domain_row.get("is_live") and not domain_row.get("reachable"): return 5 s = 20 # Live site base ssl_days = domain_row.get("ssl_expiry_days") if ssl_days is not None and ssl_days < 30: s += 15 # SSL expiring / expired — urgent upsell if not domain_row.get("ssl_valid"): s += 15 # No valid SSL cms = (domain_row.get("cms") or "").lower() if cms in KNOWN_CMS: s += 15 # Known CMS — maintenance / migration opportunity if not domain_row.get("has_mx"): s += 10 # No email = needs professional email setup if domain_row.get("ip_country") in TARGET_COUNTRIES: s += 10 server = (domain_row.get("server") or "").lower() if "shared" in server: s += 5 if local_biz_keywords(domain_row.get("page_title")): s += 5 # Kit Digital: proven buyer of IT services (Gemini-confirmed takes precedence) if domain_row.get("kit_digital"): s += 20 # Social media / GMB presence signals try: ci = json.loads(domain_row.get("contact_info") or "{}") has_social = bool(ci.get("social")) has_contact = bool(ci.get("emails") or ci.get("phones") or ci.get("whatsapp")) except Exception: has_social = False has_contact = False if not has_social: s += 5 # No social = opportunity to build presence if has_contact: s += 3 # Reachable lead — we can actually pitch them return min(s, 100) async def run_scoring(): async with aiosqlite.connect(SQLITE_PATH) as db: db.row_factory = aiosqlite.Row async with db.execute("SELECT * FROM enriched_domains") as cur: rows = [dict(r) async for r in cur] updates = [(score(r), r["domain"]) for r in rows] await db.executemany( "UPDATE enriched_domains SET score = ? WHERE domain = ?", updates ) await db.executemany( """INSERT INTO scores (domain, score) VALUES (?, ?) ON CONFLICT(domain) DO UPDATE SET score=excluded.score, scored_at=datetime('now')""", updates, ) await db.commit() return {"scored": len(updates)}