""" Informe estratégico semanal de Leads Optimizer. Se ejecuta los lunes via GitHub Actions y envía un análisis profundo a Slack. """ import json import sys import os import requests from datetime import datetime, timedelta import config from airtable_client import AirtableClient from google_ads_client import GoogleAdsClient from agent import weekly_strategic_analysis from analyzer import analyze from slack_reporter import MESES_ES MESES_ES_LOCAL = MESES_ES def _get_week_days(offset_weeks: int = 0) -> list[str]: """Devuelve los 7 días YYYY-MM-DD de la semana offset_weeks atrás (0=esta, 1=anterior).""" today = datetime.now().date() monday = today - timedelta(days=today.weekday()) - timedelta(weeks=offset_weeks) return [(monday + timedelta(days=i)).strftime("%Y-%m-%d") for i in range(7)] def _filter_games_md_by_days(games_md: dict, days: list[str]) -> dict: """Filtra MetricasDiarias de GAMes a los días indicados (formato 'DD').""" day_keys = {d[8:10] for d in days} return {k: v for k, v in games_md.items() if k in day_keys} def run_weekly(): now = datetime.now() print(f"\n{'='*55}") print(f" INFORME SEMANAL — {now.strftime('%d/%m/%Y %H:%M')}") print(f"{'='*55}\n") at = AirtableClient() gads = GoogleAdsClient() # Obtener MetricasDiarias de GAMes del mes en curso mes, anio = now.month, now.year print("Cargando GAMes...") games_rid = at.get_or_create_games_record(mes, anio) games_md = at.get_games_metricas(games_rid) # Calcular semanas this_week_days = _get_week_days(0) prev_week_days = _get_week_days(1) games_this = _filter_games_md_by_days(games_md, this_week_days) games_prev = _filter_games_md_by_days(games_md, prev_week_days) # Si la semana anterior cruza con el mes pasado, intentar cargar ese GAMes también prev_month_days = [d for d in prev_week_days if d[:7] != now.strftime("%Y-%m")] if prev_month_days: prev_mes = mes - 1 if mes > 1 else 12 prev_anio = anio if mes > 1 else anio - 1 prev_records = at.games.all(formula=f"AND({{Mes}}='{prev_mes}',{{Año}}='{prev_anio}')") if prev_records: try: prev_md = json.loads(prev_records[0]["fields"].get("MetricasDiarias") or "{}") except Exception: prev_md = {} extra = _filter_games_md_by_days(prev_md, prev_month_days) games_prev.update(extra) # Cargar métricas de campañas activas para el análisis de portfolio print("Cargando campañas activas...") campaigns = at.get_active_gacampaignmes() monthly_metrics = gads.get_monthly_metrics_all() collected = [] for campaign in campaigns: cid = campaign["google_campaign_id"] metrics = monthly_metrics.get(cid, {"cost": 0, "conversions": 0, "clicks": 0, "impressions": 0, "ctr": 0, "budget_daily": 0, "status": "UNKNOWN"}) leads = campaign.get("conv_leads_lake_mes", 0) analysis = analyze(campaign, leads, metrics) collected.append({"campaign": campaign, "metrics": metrics, "analysis": analysis, "leads": leads}) print("Generando análisis estratégico semanal con IA...") mes_nombre = MESES_ES_LOCAL.get(mes, str(mes)) analysis_text = weekly_strategic_analysis(games_this, games_prev, collected, mes_nombre) # Construir mensaje Slack if not config.SLACK_WEBHOOK_URL: print("SLACK_WEBHOOK_URL no configurada.") print("\n--- ANÁLISIS ---\n") print(analysis_text) return this_range = f"{this_week_days[0][8:10]}/{this_week_days[0][5:7]}–{this_week_days[-1][8:10]}/{this_week_days[-1][5:7]}" prev_range = f"{prev_week_days[0][8:10]}/{prev_week_days[0][5:7]}–{prev_week_days[-1][8:10]}/{prev_week_days[-1][5:7]}" blocks = [ { "type": "header", "text": {"type": "plain_text", "text": f"INFORME SEMANAL — {now.strftime('%d/%m/%Y')}"}, }, { "type": "section", "text": { "type": "mrkdwn", "text": f"_Semana actual: {this_range} | Semana anterior: {prev_range}_", }, }, {"type": "divider"}, { "type": "section", "text": { "type": "mrkdwn", "text": f"🤖 *ANÁLISIS ESTRATÉGICO SEMANAL*\n{analysis_text}", }, }, ] try: resp = requests.post(config.SLACK_WEBHOOK_URL, json={"blocks": blocks}, timeout=10) if resp.status_code != 200: print(f"⚠️ Slack respondió {resp.status_code}: {resp.text[:200]}") else: print("✓ Informe semanal enviado a Slack.") except Exception as e: print(f"⚠️ Error enviando a Slack: {e}") if __name__ == "__main__": run_weekly()