API REST desarrollada en Node.js + TypeScript + Express que permite cargar reseñas externas a los productos (autos) de los concesionarios de Top Cars, utilizando Gemini AI para el matching semántico entre reviews externas y productos internos.
Al iniciar el servidor, la API le envía a Gemini tres fuentes de datos:
internal_dealers.json— concesionarios oficialesinternal_products.json— autos por concesionarioexternal_reviews.json— reseñas recolectadas de internet
Gemini realiza un matching en dos pasos:
- Review → Dealer: identifica a qué concesionario oficial pertenece la reseña, tolerando variaciones de nombre (abreviaturas, typos, sucursales).
- Review → Producto: dentro de ese concesionario, detecta semánticamente a qué auto se refiere la reseña (ej: "furgón blanco para repartir pan" → Peugeot Partner).
El resultado se guarda en memoria como un Map<product_id, Review[]> y se consulta en O(1) por cada request.
- Node.js v18 o superior
- npm
- Una API Key de Google Gemini (gratis en aistudio.google.com)
git clone https://github.com/tu-usuario/top-cars-api.git
cd top-cars-api
npm installCreá un archivo .env en la raíz del proyecto:
GEMINI_API_KEY=tu_api_key_aqui
PORT=3000Modo desarrollo (con hot reload):
npm run devModo producción:
npm run build
npm startAl iniciar verás en consola:
Server is running on PORT: 3000
Creating reviews map...
Reviews map ready!
Devuelve las reseñas matcheadas para un producto específico.
Ejemplo:
GET http://localhost:3000/products/P-2001/reviews
Respuesta exitosa:
{
"product_id": "P-2001",
"brand": "BMW",
"model": "Serie 3",
"dealer_id": "D-200",
"dealer_name": "Premium Automotriz",
"reviews": [
{
"review_id": "G-03",
"external_dealer_name": "Premium Cars Automotriz (Stgo)",
"text": "El Serie 3 es una bala.",
"rating": 4
}
],
"success": true,
"message": "Found 1 review(s) for product 'P-2001'"
}Producto no encontrado (404):
{
"success": false,
"message": "Product 'P-9999' not found"
}Fuerza la regeneración del mapa de reviews (útil cuando se agregan nuevos productos o reseñas).
Respuesta:
{
"message": "Reviews map reloaded successfully"
}| product_id | Marca | Modelo | Concesionario |
|---|---|---|---|
| P-1001 | Toyota | Corolla Cross | Automotores Sur |
| P-2001 | BMW | Serie 3 | Premium Automotriz |
| P-3002 | Nissan | Navara | Norte Motor SpA |
| P-4002 | Suzuki | Swift | Viña Cars SpA |
| P-5002 | Ford | Ranger | Ruta 5 Motors |
| P-6001 | Subaru | Forester | Patagonia Autos |
| P-7003 | Peugeot | Partner | BioBío CarCenter |
| P-8001 | Toyota | Yaris | Cordillera Motors |
| P-9002 | Mitsubishi | Montero | Pacífico Automotriz |
| P-10001 | Hyundai | Santa Fe | Araucanía Vehículos |
| P-14003 | Jeep | Wrangler | Valdivia Motors |
| P-15004 | RAM | 700 | Atacama Drive |
src/
├── data/
│ ├── external_reviews.json
│ ├── internal_dealers.json
│ └── internal_products.json
├── routes/
│ └── products.ts
├── services/
│ └── matcher.ts
├── types/
│ └── index.ts
├── app.ts
└── server.ts
- Pre-procesado con caché en memoria: el matching con Gemini se ejecuta una sola vez al arrancar, no en cada request. Esto minimiza el uso de la API y mantiene los tiempos de respuesta en O(1).
POST /reload: simula la invalidación de caché ante la llegada de nuevos productos o reseñas, sin necesidad de reiniciar el servidor.- Descarte por ambigüedad: si una reseña puede corresponder a más de un dealer o producto, se descarta. Calidad sobre cantidad.
- TypeScript estricto: todas las estructuras de datos están tipadas con interfaces, evitando errores en runtime.