diff --git a/README.es-ES.md b/README.es-ES.md new file mode 100644 index 0000000..9d987d5 --- /dev/null +++ b/README.es-ES.md @@ -0,0 +1,425 @@ + + +# Exora + +
+ +Exora Logo + +*Raspador de inteligencia competitiva en tiempo real impulsado por las capacidades de búsqueda de Exa* + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Next.js](https://img.shields.io/badge/Next.js-13+-black?logo=next.js)](https://nextjs.org/) +[![TypeScript](https://img.shields.io/badge/TypeScript-4.9+-blue?logo=typescript)](https://www.typescriptlang.org/) +[![Tailwind CSS](https://img.shields.io/badge/TailwindCSS-3+-cyan?logo=tailwindcss)](https://tailwindcss.com/) +[![Recharts](https://img.shields.io/badge/Recharts-2+-orange?logo=chart.js)](https://recharts.org/) +[![Exa API](https://img.shields.io/badge/Exa-Search-red)](https://exa.com/) +[![Groq](https://img.shields.io/badge/Groq-LLM-purple)](https://groq.com/) +[![OpenAI](https://img.shields.io/badge/OpenAI-LLM-pink)](https://openai.com/) +[![Gemini](https://img.shields.io/badge/Gemini-LLM-blueviolet)](https://www.gemini.com/) + +• [🐛 **Reportar Error**](https://github.com/AdityaP700/Exora-task/issues) • [**Solicitar Funcionalidad**](https://github.com/AdityaP700/Exora-task/issues) + +
+ +--- + +Exora transmite un informe competitivo de nivel VC de forma progresiva: vista general instantánea de la empresa y fundadores, seguida de enriquecimiento canónico, noticias, actualizaciones de competidores, análisis de sentimiento (con transparencia mejorada) y un resumen ejecutivo. Las llamadas a APIs externas están limitadas globalmente y ahora pueden aprovechar claves API proporcionadas por el usuario (BYOK) para Exa y múltiples proveedores de LLM. + +
+ +image + +
+ +--- +## Arquitectura de Alto Nivel + +El sistema está diseñado en torno a la divulgación progresiva, la resiliencia y proveedores de inteligencia conectables. + +Diagrama Mermaid que resume las relaciones de componentes y servicios de alto nivel: + +```mermaid +flowchart LR + subgraph Client_NextJS_App [Client Next.js App] + UI[App Page / React State / SSE Consumer] + Modal[API Key Modal - BYOK] + Store[Zustand Store - keys + validation] + Charts[Sentiment & Benchmarks] + OverviewCard[CompanyOverviewCard - DQ + AI coverage] + end + + subgraph Server_API_Routes [API Routes] + Stream[/api/briefing/stream - SSE Orchestrator/] + Batch[/api/briefing - legacy batch/] + end + + subgraph Services + Canonical[Canonical Inference] + Profile[Profile Snapshot + Refinement] + ExaSvc[Exa Service - rate-limited] + LLM[LLM Service - dynamic providers] + Analysis[Analysis Service - sentiment, momentum, pulse] + end + + subgraph External_APIs [External APIs] + Exa[(Exa Search)] + Groq[(Groq LLM)] + Gemini[(Gemini LLM)] + OpenAI[(OpenAI LLM)] + end + + Modal --> Store + Store --> UI + UI -->|domain + encoded keys| Stream + Stream --> ExaSvc --> Exa + Stream --> Canonical + Stream --> Profile --> LLM + Stream --> Analysis --> LLM + LLM --> Groq + LLM --> Gemini + LLM --> OpenAI + Stream --> UI + ExaSvc --> Analysis + ExaSvc --> Profile + +``` + +### Etapas de Transmisión Progresiva +1. `overview` – TL;DR rápido + cáscara de perfil mínimo inicial. +2. `canonical` – Nombre canónico + inferencia de alias + pista de industria. +3. `profile` – Perfil enriquecido en múltiples pases (descripción, heurísticas de empleados, puntuación de calidad de datos). +4. `founders` / `socials` – Liderazgo y URLs de redes sociales. +5. `competitors` – Dominios de competidores descubiertos o heurísticos. +6. `company-news` – Últimas noticias de alta señal ordenadas por relevancia. +7. `competitor-news` – Cobertura agregada de pares. +8. `sentiment` – Sentimiento, impulso narrativo, índice de pulso, síntesis histórica y carga mejorada de transparencia de sentimiento. +9. `summary` – Puntos clave ejecutivos. +10. `done` – Señal de finalización del flujo. + +### Concurrencia y Resiliencia +* Un limitador compartido (`lib/limiter.ts`) limita las solicitudes externas concurrentes (predeterminado: 5). +* Las llamadas a LLM degradan secuencialmente a través de los proveedores proporcionados por el usuario, luego usan fallback léxico (sentimiento heurístico determinista + narrativa mínima) si no sobrevive ninguno. +* Las noticias y la puntuación de sentimiento integran filtrado de alias + expansión de consulta para mejorar la recuperación mientras se reducen los falsos positivos. + +### BYOK (Trae Tus Propias Claves) +
+ image + +
+Los usuarios proporcionan las claves API localmente (nunca se envían al almacenamiento del servidor): +* Las claves se persisten en `localStorage` mediante un `useApiKeyStore` de Zustand con estado de validación por proveedor (válido, inválido, validando, desconocido). +* Al buscar, las claves presentes se codifican en JSON, se comprimen en base64url y se adjuntan como un parámetro de consulta `keys` a la URL de SSE. +* El servidor decodifica la carga y ensambla dinámicamente la lista de proveedores activos. Los proveedores faltantes simplemente se omiten. +* La clave de Exa es obligatoria; la interfaz de usuario muestra el modal si falta. +* El `CompanyOverviewCard` muestra un insignia de cobertura de IA (contador de proveedores de LLM validados) junto con la calidad de datos del perfil (DQ). + +Diagrama de secuencia para una solicitud de transmisión típica con BYOK: + +```mermaid +sequenceDiagram + participant User + participant UI as Client UI + participant Store as Key Store (Zustand) + participant Stream as /api/briefing/stream + participant Exa as Exa API + participant LLM as llm-service + participant Providers as Groq/Gemini/OpenAI + + User->>UI: Enter domain & submit + UI->>Store: Read keys (exa, groq, gemini, openai) + UI->>Stream: SSE connect (domain + base64url(keys)) + Stream->>Stream: Decode keys & build provider list + Stream->>Exa: Fetch initial signals (overview/news) + Stream-->>UI: event: overview + Stream->>LLM: Profile refinement / sentiment (if providers) + LLM->>Providers: First available provider call + Providers-->>LLM: Response / (or failure) + alt Provider chain fails + Stream->>Stream: Lexical fallback sentiment + end + Stream-->>UI: canonical, profile, founders, socials + Stream->>Exa: Competitors & news queries + Exa-->>Stream: Results (filtered by aliases) + Stream-->>UI: company-news, competitor-news + Stream-->>UI: sentiment (metrics + enhancedSentiment) + Stream-->>UI: summary + Stream-->>UI: done +``` + +### Transparencia Mejorada del Sentimiento +
+ image + +
+El evento `sentiment` puede incluir `enhancedSentiment` (puntuación general, desglose de componentes, factores cualitativos, confianza, etiqueta de método). Las interfaces de usuario pueden exponer selectivamente esto para usuarios avanzados o depuración. + +### Puntuación de Calidad de Datos +La completitud del perfil se puntúa heurísticamente (`high` / `medium` / `low`) en función de la presencia y riqueza de los campos centrales (industria, longitud de la descripción, número de empleados, fundadores, redes sociales). Se muestra como una insignia. + +--- + +## ¿Por qué esta arquitectura? + +- Entrega progresiva: Los usuarios ven valor de inmediato (vista general + fundadores/redes sociales) mientras el análisis más profundo se carga en segundo plano. +- Límite de tasa global: Un limitador de concurrencia compartido garantiza que no se ejecuten más de 5 solicitudes externas en paralelo, evitando errores 429 de la API y suavizando la carga. +- Proveedores resilientes: Exa (noticias/menciones) + Groq/OpenAI/Gemini (LLMs) con degradaciones limpias aseguran resultados confiables. +- Pila familiar y rápida: Next.js App Router, React, TypeScript, Tailwind y Recharts ofrecen una excelente DX y rendimiento. +```mermaid +flowchart TD + %% Frontend + A[Next.js App] -->|SSE /api/briefing/stream| B[Streaming UI Components] + B --> B1[Overview: Company & Founders] + B --> B2[News Feed & Competitor News] + B --> B3[Analysis: Charts & Metrics] + B --> B4[Summary: Executive Insights] + + %% Backend + A -->|Batch /api/briefing| C[Batch REST Endpoint ] + C -->|Validate Domain| D[AI Bouncer] + C -->|Competitor Discovery| E[Groq/OpenAI/Gemini] + C -->|Fetch Mentions & News| F[Exa Service / NewsAPI Fallback] + C -->|Compute Metrics| G[Analysis Service] + C -->|Generate Summary| H[Executive Summary Service] + + %% Streaming flow + A -->|SSE /api/briefing/stream| I[Streaming Endpoint] + I --> J[Emit Stages] + J --> J1[overview] + J --> J2[founders] + J --> J3[socials] + J --> J4[competitors] + J --> J5[company-news] + J --> J6[competitor-news] + J --> J7[sentiment + metrics] + J --> J8[summary] + J --> J9[done] + + %% Services & Utilities + F --> K[Rate Limiter ] + E --> K + G --> K + F -->|Normalize Dates & Deduplicate| L[Utils ] + G --> M[Sentiment & Momentum Calculations] + H --> N[Fallbacks & Super Prompt] + + %% Data Contracts + J --> O[Types: BriefingResponse, BenchmarkMatrixItem, NewsItem, EventLogItem] + + %% Edge Cases + D --> P[Invalid Domain Handling] + F --> Q[Empty Exa Results → NewsAPI Fallback] + G --> R[Sparse Data → Default Metrics] + E --> S[LLM Failures → Safe Fallbacks] + + %% Notes + style A fill:#1f2937,stroke:#ffffff,color:#ffffff + style B fill:#111827,stroke:#ffffff,color:#ffffff + style C fill:#111827,stroke:#ffffff,color:#ffffff + style I fill:#1f2937,stroke:#ffffff,color:#ffffff + style K fill:#374151,stroke:#ffffff,color:#ffffff + style L fill:#374151,stroke:#ffffff,color:#ffffff + style M fill:#4b5563,stroke:#ffffff,color:#ffffff + style N fill:#4b5563,stroke:#ffffff,color:#ffffff + style O fill:#6b7280,stroke:#ffffff,color:#ffffff + style P fill:#b91c1c,stroke:#ffffff,color:#ffffff + style Q fill:#b91c1c,stroke:#ffffff,color:#ffffff + style R fill:#b91c1c,stroke:#ffffff,color:#ffffff + style S fill:#b91c1c,stroke:#ffffff,color:#ffffff +``` +## Pila tecnológica y fundamentación + +- Next.js (App Router): Rutas API sin servidor y componentes de Servidor/Cliente de React con excelente DX, primitivas amigables para el borde y soporte de transmisión. +- React + TypeScript: Tipado fuerte y ergonomía de componentes para flujos de UI complejos y datos por etapas. +- Tailwind CSS: Iteración rápida para una UI premium y con tema oscuro. +- Recharts: Gráficos confiables para comparaciones de sentimiento, impulso y pulso. +- Exa API: Menciones/señales de alta señal para noticias; fallback opcional de NewsAPI disponible en la ruta estándar. +- Groq/OpenAI/Gemini: LLMs para TL;DR, descubrimiento de competidores, puntuación de sentimiento y resumen. Preferimos Groq por velocidad y costo, Gemini para resúmenes rápidos y OpenAI como fallback de calidad. +- Limitador Global de Concurrencia: `lib/limiter.ts` aplica un límite máximo de 5 solicitudes concurrentes en todas las llamadas externas. + +## Flujo de datos progresivo + +1. Vista General de la Empresa (instantánea): TL;DR de una oración. +2. Fundadores + Redes Sociales (inmediato): Personas clave y enlaces de perfiles. +3. Noticias de la Empresa (temprano): Las 3 últimas noticias más relevantes para la empresa. +4. Noticias de Competidores (siguiente): Las 4 últimas noticias en competidores. +5. Sentimiento y Métricas (posterior): Índices de impulso, sentimiento y pulso para todos los dominios. +6. Resumen Ejecutivo (último): 3 ideas concisas a nivel ejecutivo. + +## Arquitectura del Backend + +- Ruta estándar (lote): `app/api/briefing/route.ts` construye la respuesta completa del informe de una vez (se mantiene para compatibilidad con versiones anteriores). +- Ruta de transmisión (progresiva): `app/api/briefing/stream/route.ts` emite Eventos Enviados por Servidor (SSE) en etapas: + - `overview`, `founders`, `socials`, `competitors`, `company-news`, `competitor-news`, `sentiment`, `summary`, `done`. +- Limitación de tasa: `lib/limiter.ts` expone un limitador compartido utilizado por: + - `lib/exa-service.ts`: todas las solicitudes de Exa + - `lib/llm-service.ts`: llamadas a Groq/OpenAI/Gemini + +## Arquitectura del Frontend + +- Página principal `app/page.tsx` se suscribe a SSE y actualiza la UI por evento. +- Vista de resumen: `CompanyOverviewCard` + `NewsFeed` + `CompetitorNews` se muestran progresivamente. +- Vista de análisis: Muestra `CompetitorBarChart` y gráficos una vez que llega `sentiment`; muestra cargadores de lo contrario. +- Vista de resumen: Muestra el TL;DR de inmediato y completa los puntos clave ejecutivos después de `summary`. + +## Estrategia de límite de tasa + +- Límite rígido: Como máximo 5 llamadas externas concurrentes en cualquier momento en toda la aplicación. +- Llamadas en lote: Las noticias de competidores se obtienen concurrentemente pero pasan por el limitador. +- Llamadas a LLM: Siempre se programan a través del mismo limitador para evitar picos. + +## Configuración de variables de entorno + +Crea `.env.local` si deseas valores predeterminados del servidor (actúan como fallback cuando no se proporcionan claves BYOK del usuario): + +- `EXA_API_KEY` (fallback del servidor — la UI aún requiere Exa vía BYOK si no se establece) +- `GROQ_API_KEY` (fallback opcional) +- `OPENAI_API_KEY` (fallback opcional) +- `GEMINI_API_KEY` (fallback opcional) +- `NEWS_API_KEY` (opcional; usado por la ruta de lote legado) + +Si un usuario proporciona claves a través del modal, estas anulan los valores de entorno para el flujo de esa sesión. + +## Ejecutar localmente + +- Instalar dependencias +- Iniciar servidor de desarrollo + +```powershell +# From the exora folder +npm install +npm run dev +``` + +Abre http://localhost:3000 e introduce un dominio de empresa (ej. stripe.com). + +## Probar la ruta de transmisión directamente + +Usa las herramientas de desarrollo de tu navegador o herramientas similares a curl para acceder a: + +``` +GET /api/briefing/stream?domain=stripe.com +``` + +Recibirás eventos como: + +``` +event: overview +{ "domain": "stripe.com", "overview": "Stripe is a payments platform..." } +``` + +## Archivos de interés + +- `app/api/briefing/stream/route.ts` - Endpoint SSE, orquesta el trabajo por etapas. +- `lib/limiter.ts` - Limitador global de concurrencia. +- `lib/exa-service.ts` - Llamadas a Exa, con límite de tasa. +- `lib/llm-service.ts` - Llamadas a Groq/OpenAI/Gemini, con límite de tasa. +- `app/page.tsx` - Consumen el flujo y renderiza progresivamente.aa +--- +## Primeros Pasos + +Sigue estos pasos para comenzar a contribuir a **Exora**: + +1. **Hacer fork y clonar el repositorio**: +```bash +git clone https://github.com//Exora-task>.git +cd +```` + +2. **Instalar dependencias**: + +```bash +npm install +``` + +3. **Encontrar un error genuino o mejora**. + Para problemas válidos, utiliza una convención de nomenclatura clara, por ejemplo: + + * `[UI/UX] :feat` → para una funcionalidad de UI/UX + * `[Backend] :fix` → para un error de backend + * `[Docs] :update` → para mejoras de documentación + +4. **Crear una rama** desde `development` (nunca `main`) antes de realizar cambios. + +5. **Enviar un Pull Request** siguiendo las directrices a continuación. + +--- + +## Directrices para Contribuyentes + +Damos la bienvenida a contribuciones de la comunidad, incluidas las que se unan a través de programas como **Hector**, **Fetched** o **Summer of Code**. +Por favor, sigue los pasos a continuación para garantizar una colaboración fluida: + +### Problemas e Informes de Errores + +* Antes de abrir un nuevo problema, **busca problemas existentes** para evitar duplicados. +* Utiliza las **plantillas de problemas** proporcionadas: + + * [] **Bug Report** – para errores, fallos o comportamiento inesperado. + * [] **Feature Request** – para nuevas ideas o mejoras. + * [] **Security Report** – para vulnerabilidades (por favor, informa de manera responsable). +* Añade pasos claros de reproducción, resultados esperados vs. reales, y capturas de pantalla/registros si es posible. + +### Prácticas de Ramas y Commits + +* Always branch from `development` (never directly from `main`). +* Use the following branch naming convention: + + * `feat/` → para nuevas funcionalidades + * `fix/` → para correcciones de errores + * `docs/` → para cambios de documentación +* Mantén los commits **atómicos** y significativos. Ejemplo: + + * ✅ `fix: resolve duplicate competitor domains` + * ✅ `feat: add contributor guidelines section` + +--- + +## Ejecutar Pruebas + +Antes de enviar un PR, ejecuta las pruebas localmente: + +```bash +npm run test +npm run lint +``` +--- + +### Solicitudes de Extracción (Pull Requests) + +* Asegúrate de que el título de tu PR siga el formato: + + * `[Feature] Add ` / `[Fix] Resolve ` +* Enlaza el problema relacionado (`Closes #123`) dentro de la descripción de tu PR. +* Sigue la plantilla y la lista de verificación para facilitar las revisiones. +* Los PR se fusionan primero en `development`, luego se promueven a `main` después de la revisión y pruebas. + +## Notas y Mejoras Futuras + +* Añadir insignias de fuente (Exa/NewsAPI) a las tarjetas de noticias para mayor transparencia. +* Cachear el descubrimiento de competidores por dominio para reducir llamadas a LLM. +* Persistir resultados parciales en localStorage durante la transmisión para resiliencia al actualizar. +* Opcional: transporte WebSocket para interacciones bidireccionales; SSE es suficiente para flujos unidireccionales. +* Evento de eco de estado de clave SSE (confirmar opcionalmente proveedores aceptados temprano). +* Almacenamiento cifrado en reposo para claves usando WebCrypto + contraseña del usuario. +* Contadores de uso de proveedores y advertencias suaves antes del agotamiento de la cuota. + +## Agradecimientos Especiales + +Gracias a todos los que contribuyen bajo programas de verano de código abierto. +Su trabajo impulsa el progreso de **Exora** + +--- + +### Muro de Contribuyentes + +Apreciamos profundamente a cada contribuyente. Tu perfil de GitHub se mostrará en nuestra sección de contribuyentes a continuación 👇 + + + + + + +--- + +Construido para una inteligencia rápida y progresiva con una UX premium.