feat: 5 fixes — dead site scoring, Kit Digital precision, social icons, GMB detection, social/GMB weighting
1. scorer: dead sites capped at 5 (was scoring HOT from SSL/CMS signals) 2. Kit Digital: require explicit kit-digital/agente-digitalizador signals; generic EU logo patterns (fondos-europeos, logo-ue, cofinanciado) removed. Gemini kit_digital_confirmed now overwrites heuristic in DB. 3. Browse table: social links replaced with compact coloured icon badges (fb/ig/in/x/tt/yt) linked to the profile URLs 4. site_analyzer: added has_gmb / gmb_url detection (Maps embed, Place links, LocalBusiness schema); fed to Gemini prompt 5. scorer: +5 no-social, +3 reachable contact; Gemini prompt includes GMB and social media management as sellable services; modal shows GMB/social status Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
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").split(","))
|
||||
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", "hotel",
|
||||
"panadería", "peluquería", "tienda",
|
||||
"fontanero", "electricista", "dentista", "clínica", "taller",
|
||||
"panadería", "peluquería", "tienda", "abogado", "gestor", "inmobili",
|
||||
}
|
||||
|
||||
|
||||
@@ -21,29 +22,53 @@ def local_biz_keywords(title: str | None) -> bool:
|
||||
|
||||
|
||||
def score(domain_row: dict) -> int:
|
||||
s = 0
|
||||
if domain_row.get("is_live"):
|
||||
s += 20
|
||||
# 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
|
||||
s += 15 # SSL expiring / expired — urgent upsell
|
||||
if not domain_row.get("ssl_valid"):
|
||||
s += 15
|
||||
s += 15 # No valid SSL
|
||||
|
||||
cms = (domain_row.get("cms") or "").lower()
|
||||
if cms in KNOWN_CMS:
|
||||
s += 15
|
||||
s += 15 # Known CMS — maintenance / migration opportunity
|
||||
|
||||
if not domain_row.get("has_mx"):
|
||||
s += 10
|
||||
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 += 10
|
||||
s += 5
|
||||
|
||||
if local_biz_keywords(domain_row.get("page_title")):
|
||||
s += 5
|
||||
# Kit Digital: proven buyer of IT services
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user