Files
DomGod/app/scorer.py

93 lines
3.0 KiB
Python
Raw Normal View History

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)}