Fix tracking discrepancy direction, improve daily metrics table, increase max_tokens
Some checks failed
Weekly Strategic Report / run (push) Has been cancelled
Some checks failed
Weekly Strategic Report / run (push) Has been cancelled
- analyzer.py: use abs() for tracking discrepancy so both directions alert - slack_reporter.py: daily table adds L.AT/L.GA/Coste/€.AT/€.GA columns; margin uses Google Ads conversions × PPL; split monthly rankings into separate blocks; fix stale margen field - run.py: leads_grupo always uses Google Ads conversions; tracking alert shows direction (over/under attribution) - agent.py: increase decide() max_tokens 700→750 to fix JSON truncation for long campaign names Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a024508062
commit
d23cb6b9c2
2
agent.py
2
agent.py
@ -228,7 +228,7 @@ def weekly_strategic_analysis(games_md_this: dict, games_md_prev_week: dict,
|
|||||||
def decide(analysis: dict) -> dict:
|
def decide(analysis: dict) -> dict:
|
||||||
response = client.messages.create(
|
response = client.messages.create(
|
||||||
model="claude-sonnet-4-6",
|
model="claude-sonnet-4-6",
|
||||||
max_tokens=700,
|
max_tokens=750,
|
||||||
system=SYSTEM_PROMPT,
|
system=SYSTEM_PROMPT,
|
||||||
messages=[{
|
messages=[{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
|
|||||||
@ -35,7 +35,7 @@ def analyze(campaign_config: dict, leads_entregados: int, ads_metrics: dict) ->
|
|||||||
else:
|
else:
|
||||||
urgencia = "EN_RITMO"
|
urgencia = "EN_RITMO"
|
||||||
|
|
||||||
# Discrepancia entre leads Airtable (ConvLeadsLakeMes) y conversiones Google
|
# Discrepancia en ambas direcciones: Google > Airtable puede indicar conversiones falsas
|
||||||
conv_leads_lake_mes = campaign_config.get("conv_leads_lake_mes", leads_entregados)
|
conv_leads_lake_mes = campaign_config.get("conv_leads_lake_mes", leads_entregados)
|
||||||
discrepancia = abs(conversiones_google - conv_leads_lake_mes)
|
discrepancia = abs(conversiones_google - conv_leads_lake_mes)
|
||||||
|
|
||||||
|
|||||||
11
run.py
11
run.py
@ -220,10 +220,8 @@ def run():
|
|||||||
|
|
||||||
if is_pmx_with_leadform:
|
if is_pmx_with_leadform:
|
||||||
leads_grupo = int(metrics.get("conversions", 0)) + leadform_conv_by_course.get(course_num, 0)
|
leads_grupo = int(metrics.get("conversions", 0)) + leadform_conv_by_course.get(course_num, 0)
|
||||||
elif is_pmx_with_companion:
|
|
||||||
leads_grupo = int(metrics.get("conversions", 0))
|
|
||||||
else:
|
else:
|
||||||
leads_grupo = leads
|
leads_grupo = int(metrics.get("conversions", 0))
|
||||||
|
|
||||||
analysis = analyze(campaign, leads_grupo, metrics)
|
analysis = analyze(campaign, leads_grupo, metrics)
|
||||||
decision = decide(analysis)
|
decision = decide(analysis)
|
||||||
@ -296,8 +294,11 @@ def run():
|
|||||||
f"Rentable: {'✅' if analysis['rentable'] else '❌'}")
|
f"Rentable: {'✅' if analysis['rentable'] else '❌'}")
|
||||||
|
|
||||||
if analysis["alerta_tracking"]:
|
if analysis["alerta_tracking"]:
|
||||||
print(f" 🚨 ALERTA TRACKING: {analysis['discrepancia_tracking']} leads de diferencia "
|
at_leads = campaign['conv_leads_lake_mes']
|
||||||
f"entre Airtable ({campaign['conv_leads_lake_mes']}) y Google Ads ({int(analysis['conversiones_google'])})")
|
ga_leads = int(analysis['conversiones_google'])
|
||||||
|
direction = "Airtable > Google (sobre-atribución?)" if at_leads > ga_leads else "Google > Airtable (conversiones falsas?)"
|
||||||
|
print(f" 🚨 ALERTA TRACKING: {analysis['discrepancia_tracking']:.0f} leads de diferencia "
|
||||||
|
f"— Airtable {at_leads} vs Google Ads {ga_leads} — {direction}")
|
||||||
|
|
||||||
print(f" Decisión: {accion_icono} {decision['accion']} "
|
print(f" Decisión: {accion_icono} {decision['accion']} "
|
||||||
f"(confianza: {decision['confianza']*100:.0f}%)")
|
f"(confianza: {decision['confianza']*100:.0f}%)")
|
||||||
|
|||||||
@ -185,35 +185,56 @@ def build_and_send(collected: list, dry_run: bool, prev_month_metricas: dict = N
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
if d not in daily_totals:
|
if d not in daily_totals:
|
||||||
daily_totals[d] = {"coste": 0.0, "ingreso_sum": 0.0}
|
daily_totals[d] = {"coste": 0.0, "ing_gads": 0.0, "ing_at": 0.0, "leads_gads": 0, "leads_at": 0}
|
||||||
daily_totals[d]["coste"] += vals.get("coste", 0)
|
daily_totals[d]["coste"] += vals.get("coste", 0)
|
||||||
daily_totals[d]["ingreso_sum"] += vals.get("ingreso", 0)
|
daily_totals[d]["ing_gads"] += vals.get("ingreso", 0) # conv_hoy × PPL
|
||||||
|
daily_totals[d]["ing_at"] += vals.get("leads_lake", 0) * ppl # leads_lake × PPL
|
||||||
|
daily_totals[d]["leads_gads"] += int(vals.get("leads", 0))
|
||||||
|
daily_totals[d]["leads_at"] += int(vals.get("leads_lake", 0))
|
||||||
|
|
||||||
|
def _eur(v: float) -> str:
|
||||||
|
return f"{v:,.0f}€".replace(",", ".")
|
||||||
|
|
||||||
|
def _marg(v: float) -> str:
|
||||||
|
return ("+" if v >= 0 else "") + f"{v:,.0f}€".replace(",", ".")
|
||||||
|
|
||||||
|
def _pct(v: float) -> str:
|
||||||
|
return ("+" if v >= 0 else "") + f"{v:.1f}%"
|
||||||
|
|
||||||
margin_table_block = None
|
margin_table_block = None
|
||||||
if daily_totals and not primer_dia_mes:
|
if daily_totals and not primer_dia_mes:
|
||||||
rows = ["Día Margen € %"]
|
hdr = f"{'Día':>3} {'L.AT':>5} {'L.GA':>5} {'Coste':>7} {'€.AT':>7} {'€.GA':>7} {'Margen':>9} {'%':>7}"
|
||||||
total_coste = total_ing = 0.0
|
sep = "─" * len(hdr)
|
||||||
|
rows = [hdr, sep]
|
||||||
|
tot = {"coste": 0.0, "ing_gads": 0.0, "ing_at": 0.0, "leads_gads": 0, "leads_at": 0}
|
||||||
for d in sorted(daily_totals):
|
for d in sorted(daily_totals):
|
||||||
coste = daily_totals[d]["coste"]
|
v = daily_totals[d]
|
||||||
ing_sum = daily_totals[d]["ingreso_sum"]
|
ing = v["ing_gads"] # margen: conv Google Ads × PPL
|
||||||
margen = ing_sum - coste
|
marg = ing - v["coste"]
|
||||||
pct = round(margen / ing_sum * 100, 1) if ing_sum > 0 else 0.0
|
pct_v = round(marg / ing * 100, 1) if ing > 0 else 0.0
|
||||||
total_coste += coste
|
for k in tot:
|
||||||
total_ing += ing_sum
|
tot[k] += v[k]
|
||||||
s_eur = ("+" if margen >= 0 else "") + f"{margen:,.0f}€".replace(",", ".")
|
rows.append(
|
||||||
s_pct = ("+" if pct >= 0 else "") + f"{pct:.1f}%"
|
f"{d:02d} {v['leads_at']:>5} {v['leads_gads']:>5}"
|
||||||
rows.append(f"{d:02d} {s_eur:>9} {s_pct:>7}")
|
f" {_eur(v['coste']):>7}"
|
||||||
total_margen = total_ing - total_coste
|
f" {_eur(v['ing_at']):>7} {_eur(v['ing_gads']):>7}"
|
||||||
total_pct = round(total_margen / total_ing * 100, 1) if total_ing > 0 else 0.0
|
f" {_marg(marg):>9} {_pct(pct_v):>7}"
|
||||||
s_tot_eur = ("+" if total_margen >= 0 else "") + f"{total_margen:,.0f}€".replace(",", ".")
|
)
|
||||||
s_tot_pct = ("+" if total_pct >= 0 else "") + f"{total_pct:.1f}%"
|
tot_ing = tot["ing_gads"]
|
||||||
rows.append("─" * 24)
|
tot_marg = tot_ing - tot["coste"]
|
||||||
rows.append(f"TOT {s_tot_eur:>9} {s_tot_pct:>7}")
|
tot_pct = round(tot_marg / tot_ing * 100, 1) if tot_ing > 0 else 0.0
|
||||||
|
rows.append(sep)
|
||||||
|
rows.append(
|
||||||
|
f"{'TOT':>3} {tot['leads_at']:>5} {tot['leads_gads']:>5}"
|
||||||
|
f" {_eur(tot['coste']):>7}"
|
||||||
|
f" {_eur(tot['ing_at']):>7} {_eur(tot['ing_gads']):>7}"
|
||||||
|
f" {_marg(tot_marg):>9} {_pct(tot_pct):>7}"
|
||||||
|
)
|
||||||
margin_table_block = {
|
margin_table_block = {
|
||||||
"type": "section",
|
"type": "section",
|
||||||
"text": {
|
"text": {
|
||||||
"type": "mrkdwn",
|
"type": "mrkdwn",
|
||||||
"text": _trunc(f"📅 *MÁRGENES POR DÍA — {MESES_ES[now.month].upper()}*\n```\n" + "\n".join(rows) + "\n```"),
|
"text": _trunc(f"📅 *MÉTRICAS POR DÍA — {MESES_ES[now.month].upper()}* _(L.AT=leads Airtable · L.GA=conv Google Ads · €.AT=fact×PPL Airtable · €.GA=fact×PPL Google Ads)_\n```\n" + "\n".join(rows) + "\n```"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user