← ☕︎ mmaria MyPublicGPT · Tutorial tutorial · junio 2026
MyPublicInbox · Expediente Digital

MyPublicGPT
Tutorial de implementación

Todo lo que necesitas para montar esto en producción, paso a paso.
⚡ Gemini 2.5 Flash ☁ Cloudflare Workers 🔑 Google AI Studio 💳 ~1€/mes
Test popups:
① Demo en vivo · ¿Qué sabes de mí?
Sujeto del informe
Elige un nombre
Ninguno seleccionado
Cooldown: 20s
Playbooks generados
0/5 esta sesión
Aún no has generado ninguno.
En esta demo, los playbooks se guardan en memoria de sesión. Al recargar la página se borran. ¿Estudiaremos save real en producción?
📂
Selecciona un nombre y pulsa el botón
para generar el expediente digital.
📂
Abriendo expediente...
Gemini 2.5 Flash · Google Search Grounding
Expediente
En producción: cooldown de 7 días por usuario — un informe gratuito semanal. En esta demo el límite es 5 por sesión para no agotar los tokens de tripada.
👇 Ver paso a paso
ⓘ Tutorial paso a paso
1
Crear el Cloudflare Worker
El Worker es el intermediario entre tu front y Gemini. La API key vive aquí encriptada — tu front jamás la toca.
VitalCloudflare5 min

Ve a Cloudflare Dashboard → Workers & Pages → Create y crea un nuevo Worker. El nombre que le pongas será parte de la URL del endpoint, por ejemplo: gemini-caso-abierto.tuusuario.workers.dev

→ Ir a Cloudflare Workers

Una vez creado, entra en Edit Worker, reemplaza el código por el contenido del fichero worker.js y pulsa Deploy.

⬇ Descargar worker.js
🔒
Origen hardcodeado por diseño. El Worker solo acepta peticiones desde el dominio que tú indiques. Busca la línea const allowed = "https://mmaria.pages.dev" y cámbiala por el dominio real de MyPublicInbox antes de deploychear.
🤖
Dudas con Cloudflare Workers? Tanto Gemini como Claude conocen perfectamente el entorno. Claude escribió el grueso de este front, por si sirve de referencia.
2
Google AI Studio: proyecto, API key y prepago
Necesitas una API key de Google AI Studio — no confundir con una key estandar de Google Cloud Console.
VitalGoogle AI10 min + pago

1. Crea un proyecto en Google AI Studio.

→ Ir a Google AI Studio

2. Crea una API key en el panel de API Keys. Cópiala ahora — la necesitarás en el paso siguiente.

3. Elige Tier 1 y añade prepago. El mínimo es 10€. Se carga a medida que consumes tokens.

→ Configurar facturación

4. Establece un Spend Cap de 1€/mes. Equivale a unas 1.500 peticiones a Gemini 2.5 Flash. Si se agota, las peticiones devuelven error 429 — controlable, sin sorpresas en la factura.

No confundas las API keys. La key de Google AI Studio es diferente de las keys de Google Cloud Console estándar. Pista: si las mezclas obtendrás errores 401/404, y lo sé porque... Exacto, porque soy así de pava 🦃
3
Encriptar la API key como secret en el Worker
La API key nunca debe estar en el código fuente en texto plano. Se guarda como variable de entorno encriptada. Si te la pillan, date por crujido.
VitalSeguridad2 min

En el Dashboard de Cloudflare, entra en tu Worker → Settings → Variables and Secrets. Añade una nueva variable de tipo Secret con este nombre exacto:

GEMINI_API_KEY

Pega el valor de tu API key y guarda. Cloudflare la encripta en reposo — ni tú podrás verla de nuevo desde el panel. El Worker la usa internamente como env.GEMINI_API_KEY.

🛡
Nunca pongas la API key en el código fuente, ni en el front, ni en ningún sitio publico. Si sospechas que ha quedado expuesta, revócala desde Google AI Studio y genera una nueva.
4
Integrar en el front: el fetch al Worker
Llamada POST al Worker, manejo de errores 502/503/429, parseo del JSON de vuelta.
VitalJavaScript
Llamada al Worker desde el front
const WORKER_URL = 'https://tu-worker.tuusuario.workers.dev';

async function generarExpediente(nombre) {
  const res = await fetch(WORKER_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ nombre, modo: 'base' })
  });
  if (!res.ok) throw new Error('HTTP ' + res.status);
  const data = JSON.parse(await res.text());
  if (data.error) throw new Error(data.error);
  return data; // { nombre, epiteto, bloques[], conclusion }
}
Manejo de errores por código HTTP
try {
  const data = await generarExpediente(nombre);
  renderizarPlaybook(data);
} catch (e) {
  const cod = e.message.match(/\d{3}/)?.[0];
  if (cod === '503') mostrarError('Pico de demanda. Reintenta.');   // tokens: intactos
  else if (cod === '429') mostrarError('Spend Cap agotado.');        // tokens: intactos
  else if (cod === '502') mostrarError('Timeout. Reintenta.');       // tokens: consumidos (probablemente)
  else mostrarError('Error: ' + e.message);                          // revisar Worker y key
}
ErrorCausaTokensAcción
503Gemini sobrecargadoIntactosReintento
429Spend Cap agotadoIntactosAmpliar cap
502Timeout Worker (tier gratis)Prob. consumidosWorker de pago
otrosConfig. errónea, CORS...VaríaRevisar Worker y key
5
Schema del JSON y fragmentación de texto
El JSON que devuelve Gemini tiene estructura fija. El texto de algunos bloques viene separado por · — un parser lo fragmenta para maquetar.
VitalJavaScript
Schema del JSON devuelto por Gemini
{
  "nombre":   "Nombre analizado",
  "epiteto":  "2-4 palabras que resumen el patrón digital",
  "bloques": [
    {
      "id":       "titular",   // o: narrativa | senales | identidad | oportunidades
      "label":    "Lo que Internet dice de ti",
      "contenido":"Texto compacto · separado con · si hay items"
    }
    // ... 5 bloques en total
  ],
  "conclusion": "Diagnóstico principal en 1 frase"
}
parseFrases() — fragmentador de texto
// Fragmenta texto separado por · en array limpio
function parseFrases(texto) {
  if (!texto) return [];
  return texto.split('·').map(f => f.trim()).filter(f => f.length > 0);
}
El Worker usa responseMimeType: "application/json" para forzar JSON puro, con sanitización de code fences como red de seguridad.
6
Renderizar el playbook: srcdoc en iframe
El playbook se renderiza como HTML completo inyectado en un iframe con srcdoc. Independiente, imprimible, exportable a PDF.
VitalHTMLPDF

El playbook no navega a otra página — se genera dinámicamente y se inyecta en un <iframe srcdoc="...">. Esto permite pantalla completa con requestFullscreen() y PDF con contentWindow.print() manteniendo estilos y fondos oscuros.

Inyectar el playbook en el iframe
function renderizarPlaybook(data) {
  const iframe = document.getElementById('playbook-iframe');
  iframe.srcdoc = construirPlaybookHTML(data); // HTML completo generado por JS
  document.getElementById('playbook-frame').classList.add('visible');
  document.getElementById('playbook-toolbar-name').textContent = data.nombre;
}

// Pantalla completa (requiere interacción directa del usuario)
function abrirFullscreen() {
  const iframe = document.getElementById('playbook-iframe');
  if (iframe.requestFullscreen) iframe.requestFullscreen();
  else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen();
}

// PDF: funciona solo en remoto (no en localhost/file://)
function descargarPDF() {
  const iframe = document.getElementById('playbook-iframe');
  if (iframe && iframe.contentWindow) iframe.contentWindow.print();
}
Limitación de fullscreen automático: los navegadores bloquean requestFullscreen() si se llama desde un setTimeout o sin interacción directa del usuario. El botón de toolbar es la solución correcta — no intentar dispararlo automáticamente al cargar el iframe.
7
Cooldown del botón y límite de sesión
Tres niveles de control para no quemar tokens: cooldown de botón, límite de sesión, y cooldown semanal en producción.
VitalUXTokens

Esta demo corre sobre un Spend Cap de 1€/mes — suficiente para probar, no para producción. En el producto real hay que implementar un cooldown de 1 semana por usuario para controlar la inversión en tokens.

function iniciaCooldown(segundos = 20) {
  const btn  = document.getElementById('btn-generar');
  const fill = document.getElementById('cooldown-fill');
  const lbl  = document.getElementById('cooldown-label');
  document.getElementById('cooldown-wrap').classList.add('visible');
  btn.disabled = true;
  fill.style.width = '100%';
  let seg = segundos;
  const iv = setInterval(() => {
    seg--;
    lbl.textContent = 'Cooldown: ' + seg + 's';
    fill.style.width = (seg / segundos * 100) + '%';
    if (seg <= 0) {
      clearInterval(iv);
      btn.disabled = false;
      document.getElementById('cooldown-wrap').classList.remove('visible');
    }
  }, 1000);
}
8
Almacenamiento con Cloudflare KV · pendiente
Los JSONs de los informes pesan ~2KB. Cloudflare KV es la opción natural para persistirlos y re-renderizarlos sin gastar tokens nuevos.
PendienteCloudflare KV

En esta demo los playbooks se guardan en un array en memoria de sesión — al recargar desaparecen. En producción necesitamos persistencia para el cooldown de 7 días, el historial de informes anteriores, y re-renderizar sin gastar tokens nuevos.

Cloudflare KV es el almacén clave-valor de Cloudflare Workers. El JSON del informe (~2KB) se guardaría con la key user_id:semana y se recuperaría en el Worker antes de llamar a Gemini si ya existe un informe de esa semana.

🤖
Nota para cuando llegue el momento: Gemini conoce bien la API de Cloudflare KV y puede generar el código de integración. La estructura de keys y TTLs merece una conversación específica antes de implementar.
Los botones Enviar por email y Solicitar asesoría del playbook están comentados en el código, en espera de que se decida la arquitectura de delivery y almacenamiento.
9
Wrangler CLI · deploy desde terminal (opcional)
Si prefieres deploychear el Worker desde línea de comandos en lugar de copiar el código en la UI de Cloudflare.
OpcionalTerminalNode.js

Wrangler es la CLI oficial de Cloudflare para Workers. Requiere Node.js. La UI del Dashboard funciona perfectamente — esto es solo si prefieres terminal.

Instalar, autenticar y deploychear
# Instalar Wrangler globalmente (requiere Node.js)
npm install -g wrangler

# Autenticarse con tu cuenta Cloudflare (abre navegador)
wrangler login

# Deploy del Worker desde la carpeta con worker.js
wrangler deploy worker.js --name tu-worker-name

# Configurar el secret (te pedirá el valor de la API key)
wrangler secret put GEMINI_API_KEY
🤖
Si algo falla con Wrangler: los errores de autenticación o configuración son los más frecuentes. Pásale el error completo a Gemini o Claude — te guiarán paso a paso.
↑ Volver arriba