diff --git a/services/api/workers/marketmute/README-VEHIQ.md b/services/api/workers/marketmute/README-VEHIQ.md index e74d1ff..538a22f 100644 --- a/services/api/workers/marketmute/README-VEHIQ.md +++ b/services/api/workers/marketmute/README-VEHIQ.md @@ -43,3 +43,13 @@ företagssidor ratsit.se/, 2 workers á 4s väntan + 2.5-5s jitter. - Utdata: telefon_ratsit.jsonl {orgnr, telefon, status, kalla, hamtat} - Hittills: ~57% telefonträff, 0 blockeringar; toppsegment ~1 dygn, hela listan ~3 dygn - hitta.se: telefon bakom "Visa nummer"-betallösning → ej använd; mrkoll.se: CF-bannad IP + +## DEFINITIVA leveranser (dedupe per orgnr + full VIES + telefon) + +- `marketmute_targets_DEFINITIV.jsonl` — 8 095 unika cold call-mål (1 776 Hög + 6 319 Medium), + 100% moms-status (vies_targets + vies_extra), telefon löpande, 1 939 med VD direkt +- `vehiq_bilbransch_DEFINITIV.jsonl` — 15 442 unika fordonsbransch-bolag (transportörer 7 248, + bilhandlare 2 286, verkstäder 1 911, entreprenad 1 393, uthyrning/leasing 1 232, + reservdelar/däck 287), 4 583 telefoner (30%, hämtning pågår), 2 484 med VD +- `mm_definitive.py` / `veh_definitive.py` — kör om när telefonkonnektorn är färdig → + 100% telefonmärkning av båda listorna diff --git a/services/api/workers/marketmute/grand_merge.py b/services/api/workers/marketmute/grand_merge.py new file mode 100644 index 0000000..50cf177 --- /dev/null +++ b/services/api/workers/marketmute/grand_merge.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""Grand final merge: ALL VIES + telefoner + encoding -> alla slutfiler.""" +import json +from collections import defaultdict + +def fix_enc(t): + if not t or "Ã" not in t: return t + try: return t.encode("latin-1").decode("utf-8") + except Exception: return t + +# 1. ALL VIES +vies = {} +for path in ("/data/0pt/output/vies_targets.jsonl", "/data/0pt/output/vies_extra.jsonl"): + try: + for line in open(path): + r = json.loads(line) + vies[r["orgnr_fmt"]] = r + except FileNotFoundError: pass +print(f"[VIES] {len(vies):,}") + +# 2. ALLA TELEFONER +tel = {} +for line in open("/data/0pt/output/telefon_ratsit.jsonl"): + r = json.loads(line) + tel[r["orgnr"]] = r.get("telefon") +tel_hits = sum(1 for v in tel.values() if v) +print(f"[TELEFON] {len(tel):,} kontrollerade, {tel_hits:,} nummer") + +# 3. MARKETMUTE-TARGETS FINAL v2 +n = 0; v = 0; t = 0 +with open("/data/0pt/output/marketmute_targets_final.jsonl", "w") as out: + for line in open("/data/0pt/output/marketmute_targets_v3.jsonl"): + rec = json.loads(line) + orgnr = rec["orgnr"]; digits = orgnr.replace("-", "") + rec["namn"] = fix_enc(rec.get("namn")); rec["verksamhet"] = fix_enc(rec.get("verksamhet")) + for p in rec.get("kontaktpersoner", []): + p["namn"] = fix_enc(p.get("namn")) + vr = vies.get(orgnr) + if vr and vr.get("moms_valid") is not None: + rec["moms_valid"] = vr["moms_valid"]; rec["momsnr"] = vr.get("momsnr") + if vr.get("moms_namn"): rec["moms_namn"] = fix_enc(vr["moms_namn"]) + v += 1 + ph = tel.get(orgnr) + if ph: + rec["telefon"] = ph; rec["telefon_kalla"] = "ratsit.se" + t += 1 + out.write(json.dumps(rec, ensure_ascii=False) + "\n"); n += 1 +print(f"[MARKETMUTE] {n:,} mål · moms: {v:,} · telefon: {t:,}") + +# 4. VEHIQ BILBRANSCH v2 (med telefon + full VIES) +n = 0; t = 0; v = 0 +with open("/data/0pt/output/vehiq_bilbransch_final.jsonl", "w") as out: + for line in open("/data/0pt/output/vehiq_bilbransch.jsonl"): + rec = json.loads(line) + orgnr = rec["orgnr"]; digits = orgnr.replace("-", "") + rec["namn"] = fix_enc(rec.get("namn")); rec["verksamhet"] = fix_enc(rec.get("verksamhet")) + for p in rec.get("kontaktpersoner", []): + p["namn"] = fix_enc(p.get("namn")) + vr = vies.get(orgnr) + if vr and vr.get("moms_valid") is not None: + rec["moms_valid"] = vr["moms_valid"]; v += 1 + ph = tel.get(orgnr) + if ph: + rec["telefon"] = ph; rec["telefon_kalla"] = "ratsit.se"; t += 1 + out.write(json.dumps(rec, ensure_ascii=False) + "\n"); n += 1 +print(f"[VEHIQ-BILBRANSCH] {n:,} · telefon: {t:,} · moms: {v:,}") diff --git a/services/api/workers/marketmute/mm_definitive.py b/services/api/workers/marketmute/mm_definitive.py new file mode 100644 index 0000000..efc7eb2 --- /dev/null +++ b/services/api/workers/marketmute/mm_definitive.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +"""DEFINITIV MarketMute: dedupe per orgnr + ALL VIES + telefon + encoding.""" +import json + +def fix_enc(t): + if not t or "Ã" not in t: return t + try: return t.encode("latin-1").decode("utf-8") + except Exception: return t + +vies = {} +for path in ("/data/0pt/output/vies_targets.jsonl", "/data/0pt/output/vies_extra.jsonl"): + try: + for line in open(path): + r = json.loads(line) + if r.get("orgnr_fmt") and r.get("moms_valid") is not None: + vies[r["orgnr_fmt"]] = r + except FileNotFoundError: + pass +print(f"[VIES] {len(vies):,} unika med status") + +tel = {} +for line in open("/data/0pt/output/telefon_ratsit.jsonl"): + r = json.loads(line) + if r.get("telefon"): + tel[r["orgnr"]] = r["telefon"] +print(f"[TELEFON] {len(tel):,} nummer (delresultat, konnektorn kör vidare)") + +best = {} +for line in open("/data/0pt/output/marketmute_targets_v3.jsonl"): + rec = json.loads(line) + o = rec["orgnr"] + if o not in best or rec["cold_call_score"] > best[o]["cold_call_score"]: + best[o] = rec + +targets = sorted(best.values(), key=lambda x: -x["cold_call_score"]) +n = momsv = telv = vd_n = hog = 0 +with open("/data/0pt/output/marketmute_targets_DEFINITIV.jsonl", "w") as out: + for rec in targets: + orgnr = rec["orgnr"] + digits = orgnr.replace("-", "") + rec["namn"] = fix_enc(rec.get("namn")) + rec["verksamhet"] = fix_enc(rec.get("verksamhet")) + for p in rec.get("kontaktpersoner", []): + p["namn"] = fix_enc(p.get("namn")) + vr = vies.get(orgnr) + rec["moms_valid"] = vr["moms_valid"] if vr else rec.get("moms_valid") + rec["momsnr"] = (vr or {}).get("momsnr") or f"SE{digits}01" + if vr and vr.get("moms_namn"): + rec["moms_namn"] = fix_enc(vr["moms_namn"]) + if rec.get("moms_valid") is not None: + momsv += 1 + ph = tel.get(orgnr) + if ph: + rec["telefon"] = ph + rec["telefon_kalla"] = "ratsit.se" + telv += 1 + if rec.get("har_vd"): + vd_n += 1 + if rec["cold_call_klass"] == "Hög sannolikhet": + hog += 1 + out.write(json.dumps(rec, ensure_ascii=False) + "\n") + n += 1 +print(f"[DEFINITIV] {n:,} unika mål - Hog: {hog:,} - Medium: {n-hog:,}") +print(f" moms: {momsv:,} ({momsv/n*100:.0f}%) - telefon: {telv:,} - VD: {vd_n:,}") diff --git a/services/api/workers/marketmute/veh_definitive.py b/services/api/workers/marketmute/veh_definitive.py new file mode 100644 index 0000000..1ec5309 --- /dev/null +++ b/services/api/workers/marketmute/veh_definitive.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +"""DEFINITIV VehIQ-bilbransch: dedupe per orgnr + telefon + VIES + encoding.""" +import json + +def fix_enc(t): + if not t or "Ã" not in t: return t + try: return t.encode("latin-1").decode("utf-8") + except Exception: return t + +vies = {} +for path in ("/data/0pt/output/vies_targets.jsonl", "/data/0pt/output/vies_extra.jsonl"): + try: + for line in open(path): + r = json.loads(line) + if r.get("orgnr_fmt") and r.get("moms_valid") is not None: + vies[r["orgnr_fmt"]] = r + except FileNotFoundError: + pass + +tel = {} +for line in open("/data/0pt/output/telefon_ratsit.jsonl"): + r = json.loads(line) + if r.get("telefon"): + tel[r["orgnr"]] = r["telefon"] + +best = {} +for line in open("/data/0pt/output/vehiq_bilbransch.jsonl"): + rec = json.loads(line) + o = rec["orgnr"] + if o not in best or (rec.get("fordonssrelevans_score") or 0) > (best[o].get("fordonssrelevans_score") or 0): + best[o] = rec + +targets = sorted(best.values(), key=lambda x: -(x.get("fordonssrelevans_score") or 0)) +n = telv = momsv = vd_n = 0 +from collections import Counter +seg = Counter() +with open("/data/0pt/output/vehiq_bilbransch_DEFINITIV.jsonl", "w") as out: + for rec in targets: + orgnr = rec["orgnr"] + rec["namn"] = fix_enc(rec.get("namn")) + rec["verksamhet"] = fix_enc(rec.get("verksamhet")) + for p in rec.get("kontaktpersoner", []): + p["namn"] = fix_enc(p.get("namn")) + vr = vies.get(orgnr) + if vr: + rec["moms_valid"] = vr["moms_valid"] + momsv += 1 + ph = tel.get(orgnr) + if ph: + rec["telefon"] = ph + rec["telefon_kalla"] = "ratsit.se" + telv += 1 + if rec.get("har_vd"): + vd_n += 1 + seg[rec["segment"]] += 1 + out.write(json.dumps(rec, ensure_ascii=False) + "\n") + n += 1 +print(f"[VEHIQ-DEFINITIV] {n:,} unika bolag") +print(f" telefon: {telv:,} ({telv/n*100:.0f}%) - moms-status: {momsv:,} - VD: {vd_n:,}") +print(" segment:", dict(seg.most_common()))