{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  },
  "colab": {
   "name": "Kit de agentes de IA para CRM — HIKE & FOXTER",
   "provenance": []
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "![HIKE & FOXTER](https://hikefoxter.com/main-logo-black.svg)\n\n# Kit de agentes de IA para CRM — pruébalo en tu navegador, sin instalar nada\n\nEste notebook ejecuta los **5 agentes reales del kit** (basados en el ADK de\nGoogle) en los servidores de Google Colab: no instalas nada en tu ordenador.\n\n**Qué necesitas:** una cuenta de Google y una API key gratuita (te guiamos en\nel paso 1 — se consigue en 2 minutos, sin tarjeta).\n\n**Cómo se usa:** menú **Entorno de ejecución → Ejecutar todo** (en inglés:\n*Runtime → Run all*). La primera vez tarda ~2 minutos en preparar el entorno;\ncuando llegue a la celda de la clave, se detendrá y te pedirá pegarla.\n\n> Si Colab muestra el aviso *\"Este notebook no es de Google\"*, pulsa\n> **Ejecutar de todos modos**: es normal para cualquier notebook externo. El\n> código es abierto (licencia MIT) y puedes leerlo entero aquí mismo.\n",
   "id": "celda-00"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Paso 1 — Consigue tu API key gratuita (2 minutos)\n\n1. Abre [aistudio.google.com/apikey](https://aistudio.google.com/apikey) en\n   otra pestaña, con tu cuenta de Google.\n2. Pulsa el botón **Create API key** y copia la clave (empieza por `AIza…`).\n3. Vuelve aquí: la celda del paso 3 te pedirá pegarla.\n\nEs gratis y no pide tarjeta: la capa gratuita de Google AI Studio sobra para\nprobar el kit.\n\n<details><summary>💡 Tip si vas a volver varias veces</summary>\n\nGuarda la clave en los <b>Secretos de Colab</b> (icono de la llave 🔑 en la\nbarra izquierda → <i>Añadir secreto</i> → nombre <code>GOOGLE_API_KEY</code> →\npega la clave → activa <i>Acceso desde el notebook</i>). Este notebook la\ndetecta solo y no volverá a pedírtela.\n</details>\n",
   "id": "celda-01"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "# Paso 2 — Instalar el ADK de Google (~1 minuto, solo la primera vez)\n%pip install -q \"google-adk>=2.5.0\"\nprint(\"✅ Listo: ADK de Google instalado.\")\n",
   "id": "celda-02"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "# Paso 2b — Descargar el kit de agentes desde hikefoxter.com\nimport os, zipfile, urllib.request\n\nKIT_DIR = \"kit-agentes-ia-crm\"\nKIT_URL = \"https://hikefoxter.com/kit-agentes-ia-crm.zip\"\n\nif os.path.isdir(KIT_DIR):\n    print(\"✅ El kit ya está descargado.\")\nelse:\n    try:\n        if not os.path.exists(\"kit-agentes-ia-crm.zip\"):\n            urllib.request.urlretrieve(KIT_URL, \"kit-agentes-ia-crm.zip\")\n        with zipfile.ZipFile(\"kit-agentes-ia-crm.zip\") as z:\n            z.extractall(\".\")\n        print(\"✅ Kit descargado y descomprimido: 5 agentes disponibles.\")\n    except Exception as e:\n        print(\"⚠️ No se pudo descargar el kit automáticamente:\", e)\n        print()\n        print(\"Plan B: descarga el ZIP desde https://hikefoxter.com/kit-agentes-ia,\")\n        print(\"súbelo aquí con el icono de carpeta 📁 de la barra izquierda (botón subir),\")\n        print(\"y vuelve a ejecutar esta celda.\")\n",
   "id": "celda-03"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "# Paso 3 — Tu API key (se detendrá aquí para que la pegues)\nimport os\nfrom getpass import getpass\n\napi_key = \"\"\ntry:\n    from google.colab import userdata  # Secretos de Colab, si los configuraste\n    api_key = userdata.get(\"GOOGLE_API_KEY\") or \"\"\n    if api_key:\n        print(\"✅ API key cargada desde los Secretos de Colab.\")\nexcept Exception:\n    pass\n\nif not api_key:\n    api_key = getpass(\"Pega aquí tu API key y pulsa Enter (no se verá en pantalla): \").strip()\n\nif not api_key:\n    raise SystemExit(\"No has introducido ninguna clave. Vuelve a ejecutar esta celda.\")\nif not api_key.startswith(\"AIza\"):\n    print(\"⚠️ Aviso: las claves de AI Studio suelen empezar por 'AIza'. Si falla, revísala.\")\n\nos.environ[\"GOOGLE_API_KEY\"] = api_key\nos.environ[\"GOOGLE_GENAI_USE_VERTEXAI\"] = \"FALSE\"\nprint(\"✅ Clave configurada. Ya puedes hablar con los agentes.\")\n",
   "id": "celda-04"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "# Paso 4 — Cargar los 5 agentes y preparar el chat\nimport sys\n\nsys.path.insert(0, os.path.abspath(f\"{KIT_DIR}/agentes\"))\n\nfrom coordinador_crm.agent import root_agent as coordinador\nfrom cualificador_leads.agent import build_agent as _b_cualificador\nfrom enriquecedor_cuentas.agent import build_agent as _b_enriquecedor\nfrom seguimiento_deals.agent import build_agent as _b_seguimiento\nfrom limpieza_datos.agent import build_agent as _b_limpieza\n\n# Instancias propias para los especialistas: en el ADK un agente solo puede\n# tener un padre, y los sub-agentes del coordinador ya están ocupados.\ncualificador = _b_cualificador()\nenriquecedor = _b_enriquecedor()\nseguimiento = _b_seguimiento()\nlimpieza = _b_limpieza()\n\nfrom google.adk.runners import InMemoryRunner\n\n_runners = {}\n\nasync def preguntar(agente, mensaje, ver_tools=False):\n    \"\"\"Envía un mensaje al agente y muestra su respuesta.\n\n    Cada agente mantiene su conversación entre llamadas (multi-turno).\n    Con ver_tools=True muestra también las llamadas a herramientas.\n    \"\"\"\n    runner = _runners.setdefault(agente.name, InMemoryRunner(agente))\n    await runner.run_debug(mensaje, session_id=f\"colab-{agente.name}\", verbose=ver_tools)\n\ndef nueva_conversacion(agente):\n    \"\"\"Olvida la conversación anterior con ese agente.\"\"\"\n    _runners.pop(agente.name, None)\n    print(f\"🧹 Conversación con {agente.name} reiniciada.\")\n\nprint(\"✅ Agentes cargados: coordinador, cualificador, enriquecedor, seguimiento, limpieza\")\n",
   "id": "celda-05"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "---\n\n## A partir de aquí: habla con los agentes\n\nCada celda es una conversación de ejemplo contra el **mini-CRM de prueba**\nincluido en el kit (leads, deals y contactos ficticios — no necesitas conectar\nnada tuyo). Ejecútalas en orden, o cambia el texto entre comillas por tu\npropia pregunta: siempre con `await preguntar(agente, \"…\")`.\n\n| Agente | Qué hace |\n|---|---|\n| `cualificador` | Puntúa leads 0–100 con rúbrica BANT y deriva la etapa |\n| `enriquecedor` | Completa fichas de empresa sin pisar datos existentes |\n| `seguimiento` | Detecta deals estancados y redacta la reactivación |\n| `limpieza` | Duplicados y fusiones con confirmación humana |\n| `coordinador` | Recibe cualquier petición y delega en el especialista |\n",
   "id": "celda-06"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "### 🎯 Cualificador de leads\n\nLaura Gómez escribió pidiendo una demo \"con presupuesto aprobado\". Pedro\nMartín es un estudiante con un Gmail. Mira cómo el agente los distingue — y\npor qué la etapa (SQL/MQL/NUTRIR) la deriva la regla de negocio, no el humor\ndel modelo.\n",
   "id": "celda-07"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "await preguntar(cualificador, \"Cualifica el lead de laura.gomez@nortex.es y justifica la puntuación.\")\n",
   "id": "celda-08"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "# La conversación continúa: el agente recuerda el turno anterior.\nawait preguntar(cualificador, \"¿Y el resto de leads nuevos? Dame la ronda completa ordenada de mejor a peor.\")\n",
   "id": "celda-09"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "### 📈 Seguimiento de deals\n\nHay un deal de 42.000 € parado 21 días. El agente no escribe un \"¿qué tal\ntodo?\": recupera el historial real y retoma la última conversación.\n",
   "id": "celda-10"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "await preguntar(seguimiento, \"Revisa qué deals llevan parados más de 15 días y redáctame el email de reactivación para el más urgente.\")\n",
   "id": "celda-11"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "### 🏢 Enriquecedor de cuentas — con la trazabilidad a la vista\n\nEsta celda activa `ver_tools=True`: fíjate en las **llamadas a herramientas**\n(qué función ejecuta el agente, con qué argumentos, qué devuelve). Esa\ntrazabilidad es la diferencia entre un agente y un chatbot.\n",
   "id": "celda-12"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "await preguntar(enriquecedor, \"Completa la ficha de blaumar-hotels.com y dime qué aplicas y qué no, con su confianza.\", ver_tools=True)\n",
   "id": "celda-13"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "### 🧹 Limpieza de datos — el patrón de confirmación humana\n\nLa joya del kit para enseñar a dirección: hay dos fichas de Laura Gómez\nduplicadas. El agente **no fusiona nada** hasta que un humano confirma el par\nconcreto — lo impone el código de la herramienta (`confirmar=True`), no la\nbuena voluntad del modelo.\n",
   "id": "celda-14"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "await preguntar(limpieza, \"Busca contactos duplicados y muéstrame la previsualización de la fusión.\")\n",
   "id": "celda-15"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "# Solo ahora, con confirmación explícita del par, la fusión se ejecuta:\nawait preguntar(limpieza, \"Confirmo: fusiona C-002 en C-001.\")\n",
   "id": "celda-16"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "### 🧭 Coordinador — un único punto de entrada\n\nEl agente raíz: entiende tu petición y transfiere la conversación al\nespecialista adecuado (patrón multi-agente del ADK con `sub_agents`).\n",
   "id": "celda-17"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "await preguntar(coordinador, \"¿Qué leads nuevos tenemos y cuáles merecen una llamada hoy?\")\n",
   "id": "celda-18"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "# ✏️ TU TURNO — cambia el texto por lo que quieras probar.\n# Para empezar una conversación de cero: nueva_conversacion(coordinador)\nawait preguntar(coordinador, \"Prepárame la mañana: leads a llamar, deals a reactivar y duplicados a revisar.\")\n",
   "id": "celda-19"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "---\n\n## Si algo falla\n\n- **`API_KEY_INVALID` o error 400** → vuelve a ejecutar el Paso 3 y pega la\n  clave completa (empieza por `AIza`).\n- **Error 429 / `RESOURCE_EXHAUSTED`** → has agotado el ritmo de la capa\n  gratuita; espera un minuto y reintenta.\n- **`NameError: preguntar is not defined`** → has ejecutado celdas sueltas\n  sin las de arriba. Menú **Entorno de ejecución → Ejecutar todo**.\n- **Colab se desconectó por inactividad** → **Ejecutar todo** de nuevo. Las\n  conversaciones empiezan de cero: el mini-CRM vive en memoria (los \"cambios\"\n  de los agentes no persisten, es un entorno de pruebas seguro).\n- **¿Y la interfaz web `adk web` que sale en la guía?** → no funciona en\n  Colab (no expone puertos). Este notebook ES la experiencia completa aquí;\n  la interfaz web es para tu ordenador (ver `GUIA-RAPIDA.md` del kit).\n",
   "id": "celda-20"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "---\n\n## ¿Te ha gustado? Siguientes pasos\n\n1. **Para tu equipo no técnico** → carpeta `sin-codigo/` del kit: los 5\n   agentes como prompts para ChatGPT, Claude o Gemini (aceptan hasta un\n   export CSV de tu CRM).\n2. **La vía técnica en tu ordenador** → `GUIA-RAPIDA.md` (interfaz `adk web`\n   incluida).\n3. **Conectarlo a tu CRM real** → guía completa en\n   [hikefoxter.com/kit-agentes-ia/guia](https://hikefoxter.com/kit-agentes-ia/guia).\n\n¿Quieres que estos agentes trabajen sobre tu HubSpot de verdad, con garantías\nde producción? Es literalmente nuestro trabajo:\n**[Agenda 30 minutos con HIKE & FOXTER](https://crm.hikefoxter.com/meetings/acompany)** — sin compromiso.\n\n<details><summary>⚙️ Avanzado: usar Claude, GPT-4o o Mistral en vez de Gemini</summary>\n\nTambién funciona aquí: ejecuta <code>%pip install -q litellm</code>, define\n<code>os.environ[\"HF_KIT_MODEL\"] = \"anthropic/claude-sonnet-4-5\"</code> (y su\n<code>ANTHROPIC_API_KEY</code>) <b>antes</b> del Paso 4, y reinicia el entorno\nde ejecución. Detalle en <code>docs/05-elegir-modelo.md</code> del kit.\n</details>\n\n---\n\n© 2026 HIKE & FOXTER · [hikefoxter.com](https://hikefoxter.com) · Licencia MIT\n",
   "id": "celda-21"
  }
 ]
}
