Generador de Resúmenes para Reuniones
Toma un nombre de empresa y un contacto opcional. Investiga la empresa mediante Tavily. Sintetiza un resumen de una página para antes de la llamada con Gemini. Opcionalmente, guárdalo en Notion.
Regla crítica: NO INVENTES DETALLES. Cada hecho, cifra y afirmación en el resumen debe provenir de un resultado de búsqueda de Tavily. Marca cualquier sección sin datos de búsqueda como "Información pública limitada encontrada". Nunca fabriques montos de financiación, recuentos de empleados ni detalles de productos.
Paso 1: Verificación de Configuración
Confirma las variables de entorno requeridas:
echo "TAVILY_API_KEY: ${TAVILY_API_KEY:+set}"
echo "GEMINI_API_KEY: ${GEMINI_API_KEY:+set}"
echo "NOTION_TOKEN: ${NOTION_TOKEN:-no establecido}"
echo "NOTION_DATABASE_ID: ${NOTION_DATABASE_ID:-no establecido}"
Si falta TAVILY_API_KEY: Detente. Indica al usuario: "TAVILY_API_KEY es obligatorio. Consíguelo en app.tavily.com. Añádelo a tu archivo .env."
Si falta GEMINI_API_KEY: Detente. Indica al usuario: "GEMINI_API_KEY es obligatorio. Consíguelo en aistudio.google.com. Añádelo a tu archivo .env."
Si falta NOTION_TOKEN o NOTION_DATABASE_ID: Continúa. El resumen se mostrará solo como texto. Se omite el guardado en Notion.
Confirma que la entrada está presente. El usuario debe proporcionar al menos un nombre de empresa. Si no se proporciona, pregunta: "¿Con qué empresa tienes la reunión?"
Paso 2: Recopilar Contexto
Reúne lo siguiente. Pregunta solo por lo que falte.
Obligatorio:
- Nombre de la empresa (o dominio/URL si se proporciona)
- Fecha de la reunión
Opcional (no bloquees si falta):
- Nombre y cargo del contacto
- Tipo de reunión (descubrimiento, demo, seguimiento, QBR)
- Temas u objetivos específicos que el usuario quiera tratar
Si el usuario proporciona una URL o dominio de empresa, úsalo para hacer las consultas de Tavily más precisas (ej. site:example.com o incluye el dominio en los términos de búsqueda).
Paso 3: Investigar con Tavily
Ejecuta estas búsquedas en secuencia. Cada una apunta a una sección del resumen. Guarda los mejores resultados de cada una (título, URL, fragmento de contenido, puntuación).
Mantén los resultados con puntuación >= 0.5. Si una búsqueda devuelve 0 resultados que cumplan, marca esa sección como "Información pública limitada encontrada."
Búsqueda 1: Visión general de la empresa
curl -s -X POST "https://api.tavily.com/search" \
-H "Content-Type: application/json" \
-d '{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "\"EMPRESA\" overview founded employees headquarters",
"search_depth": "advanced",
"max_results": 5,
"include_answer": true
}'
Búsqueda 2: Noticias recientes (últimos 30 días)
curl -s -X POST "https://api.tavily.com/search" \
-H "Content-Type: application/json" \
-d '{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "\"EMPRESA\" news announcement",
"search_depth": "advanced",
"max_results": 5,
"include_answer": true,
"topic": "news",
"time_range": "month"
}'
Búsqueda 3: Stack tecnológico
curl -s -X POST "https://api.tavily.com/search" \
-H "Content-Type: application/json" \
-d '{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "\"EMPRESA\" technology stack engineering infrastructure tools",
"search_depth": "advanced",
"max_results": 5,
"include_answer": true
}'
Búsqueda 4: Producto y precios
curl -s -X POST "https://api.tavily.com/search" \
-H "Content-Type: application/json" \
-d '{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "\"EMPRESA\" product features pricing use case",
"search_depth": "advanced",
"max_results": 5,
"include_answer": true
}'
Búsqueda 5: Competidores
curl -s -X POST "https://api.tavily.com/search" \
-H "Content-Type: application/json" \
-d '{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "\"EMPRESA\" competitors alternatives vs",
"search_depth": "advanced",
"max_results": 5,
"include_answer": true
}'
Búsqueda 6: Financiación y crecimiento
curl -s -X POST "https://api.tavily.com/search" \
-H "Content-Type: application/json" \
-d '{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "\"EMPRESA\" funding raised valuation growth",
"search_depth": "advanced",
"max_results": 5,
"include_answer": true
}'
Si se proporciona un nombre de contacto, ejecuta dos búsquedas más:
Búsqueda 7: Perfil del contacto
curl -s -X POST "https://api.tavily.com/search" \
-H "Content-Type: application/json" \
-d '{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "\"NOMBRE_CONTACTO\" \"EMPRESA\" role title",
"search_depth": "advanced",
"max_results": 5,
"include_answer": true
}'
Búsqueda 8: Trayectoria del contacto
curl -s -X POST "https://api.tavily.com/search" \
-H "Content-Type: application/json" \
-d '{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "\"NOMBRE_CONTACTO\" background career LinkedIn",
"search_depth": "advanced",
"max_results": 5,
"include_answer": true
}'
Paso 4: Sintetizar con Gemini
Lee completamente references/brief-format.md. Lee references/output-template.md y usa la plantilla.
Escribe la solicitud a Gemini en un archivo temporal:
cat > /tmp/meeting-brief-request.json << 'ENDJSON'
{
"system_instruction": {
"parts": [{
"text": "Eres un analista de investigación GTM que prepara un resumen de una página para antes de una reunión comercial o de desarrollo de negocio. Reglas: Cada afirmación debe citar una URL de origen de la investigación proporcionada. Usa el formato 'Porque [hallazgo de la investigación], menciona [punto] para [objetivo]' para los puntos de conversación. No hay datos inventados. Si una sección no tiene datos de investigación, escribe 'Información pública limitada encontrada.' Sin guiones largos. Sin palabras prohibidas. Menos de 400 palabras en total. El resumen debe poder ser escaneado en 3 minutos."
}]
},
"contents": [{
"parts": [{
"text": "RESULTADOS_DE_INVESTIGACION_E_INSTRUCCIONES_AQUÍ"
}]
}],
"generationConfig": {
"temperature": 0.3,
"maxOutputTokens": 2500
}
}
ENDJSON
curl -s -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d @/tmp/meeting-brief-request.json \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d['candidates'][0]['content']['parts'][0]['text'])"
Reemplaza RESULTADOS_DE_INVESTIGACION_E_INSTRUCCIONES_AQUÍ con:
- Todos los resultados de búsqueda de Tavily (título, URL, fragmento de contenido por resultado)
- La estructura de la plantilla de resumen de output-template.md
- El nombre de la empresa, nombre del contacto (si se proporciona), fecha de la reunión, tipo de reunión (si se proporciona)
Paso 5: Autoverificación
Revisa antes de presentar:
- No hay datos inventados. Cada hecho tiene una URL de origen de los resultados de Tavily.
- Los puntos de conversación usan el formato "Porque [hallazgo], menciona [punto] para [objetivo]"
- Sin guiones largos en ninguna línea
- Sin palabras prohibidas
- El resumen tiene menos de 400 palabras
- La sección de Tomador de Decisiones dice "No especificado" si no se proporcionó ningún contacto
- Las secciones sin datos dicen "Información pública limitada encontrada" en lugar de adivinar
- Las preguntas abiertas son específicas de esta empresa, no genéricas
Corrige cualquier infracción antes de presentar.
Paso 6: Mostrar o Guardar en Notion
Presenta el resumen completo en un bloque de código.
Si tanto NOTION_TOKEN como NOTION_DATABASE_ID están configurados, pregunta: "¿Guardar este resumen en Notion?"
Tras la confirmación:
cat > /tmp/notion-brief-payload.json << 'ENDJSON'
{
"parent": { "database_id": "ID_BASE_DE_DATOS_NOTION_AQUÍ" },
"properties": {
"Name": {
"title": [{ "text": { "content": "Resumen Reunión: EMPRESA, FECHA" } }]
},
"Date": {
"date": { "start": "AAAA-MM-DD" }
}
},
"children": [
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [{ "type": "text", "text": { "content": "CONTENIDO_DEL_RESUMEN_AQUÍ" } }]
}
}
]
}
ENDJSON
curl -s -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_TOKEN" \
-H "Content-Type: application/json" \
-H "Notion-Version: 2022-06-28" \
-d @/tmp/notion-brief-payload.json
Después de publicar: "Resumen guardado en Notion. Revisa tu base de datos."
Si Notion no está configurado: presenta solo el resumen. No menciones Notion.