Feat/llm chatbot frontend#3
Merged
Merged
Conversation
Documentos meta del proyecto para facilitar la participación inclusiva y la reutilización por terceros (criterio de código abierto del hackathon). - CONTRIBUTING.md: flujo de PRs, conventional commits, áreas donde se busca ayuda, distinción entre backend Python y frontend web/. - CODE_OF_CONDUCT.md: Contributor Covenant 2.1 en español.
El frontend web/ que llega en commits posteriores requiere excluir node_modules, .next, .env y archivos de DB local. Las reglas Python preexistentes se mantienen intactas, solo se anclan con / inicial las que apuntan a carpetas del root (build/, lib/, dist/, etc.) para evitar colisiones con subdirectorios como web/src/lib/.
Estructura inicial del frontend conversacional que actuará como centro de comandos del sistema. Stack base: - Next.js 14 (App Router) + TypeScript estricto - Tailwind CSS + shadcn/ui (componentes accesibles, estilo "new-york") - Layout raíz en español con fuente system + Toaster (sonner) - Logo y favicon corporativos en color verde #1a531a Incluye los primitivos shadcn que se usan en pantallas siguientes: Button, Input, Label, Card, Dialog, Select, Table, Textarea, Badge, Sonner. El page.tsx raíz redirige a /orders si hay sesión o /login en caso contrario (la lógica de sesión llega en el commit de auth).
…licante Modelo de datos canónico para el dominio de reparto en última milla. Tablas: - User (ADMIN | DRIVER), Vehicle, Customer - Order: pedido con franja horaria, dirección, lat/lng cacheados, estado - Route + RouteStop: rutas planificadas con polyline OSRM persistida y paradas ordenadas por sequence con ETA planificada - Incident: averías, paquetes no entregables, tráfico, etc. - ChatSession + ChatMessage: auditoría completa del LLM con tool calls serializados (permite reproducir y debuggear conversaciones) - GeocodeCache: caché persistente de Nominatim (rate limit 1 req/s) Las lat/lng de cada Order y la polyline de cada Route se almacenan cacheadas para evitar re-llamar a APIs externas al refrescar páginas. Seed: - 2 admins + 3 conductores con bcrypt (admin/admin123, juan/juan123, ...) - 3 furgonetas con capacidades distintas - 30 clientes con nombres reales - 47 pedidos repartidos por 14 barrios de Alicante con coords reales pre-computadas (Centro, Playa San Juan, Albufereta, Vistahermosa, San Blas, Carolinas, Benalúa, Garbinet, Babel, Florida, Pla, Altozano). - Mezcla de estados realistas: 30 PENDING hoy, 5 IN_TRANSIT, 5 DISPATCHED, 10 DELIVERED ayer, 2 FAILED ayer. Las direcciones reales pre-geocodificadas evitan martillear Nominatim durante la demo y garantizan reproducibilidad. .env.example documenta todas las variables sin filtrar secretos reales.
Sistema de sesión simple sin OAuth, suficiente para piloto interno: - lib/auth.ts: sign/verify JWT, cookies httpOnly + sameSite=lax, bcrypt para passwords, helper getSession() lee la sesión en server components. - middleware.ts: protege /dashboard/* y /api/*, redirige a /login si no hay sesión. Excluye /api/auth/login para evitar bucle. - API: /api/auth/login (zod-validated), /api/auth/logout, /api/auth/me. - /login: pantalla con branding verde corporativo, gradient #0d2f0d→#1a531a, logo SVG y muestra los usuarios demo para facilitar la prueba. - Sidebar compartida con navegación entre Pedidos / Chatbot / Rutas y botón de cerrar sesión. - Layout del grupo (dashboard) con auth guard server-side. Seguridad: bcrypt rounds bajos (8) para velocidad de seed - documentar en README que en producción debe subirse a 12+.
Wrappers ligeros sobre los dos servicios públicos abiertos que el sistema consume para routing y geocoding: - lib/osrm.ts: clientes para los endpoints /route y /trip de router.project-osrm.org. /trip resuelve el TSP devolviendo el orden óptimo de paradas. Ambos cachean en memoria por hash de coordenadas para minimizar la presión sobre el servicio público (gratuito) y acelerar respuestas durante la demo. Decodifica polylines polyline6. - lib/nominatim.ts: geocoding con throttle de 1 req/segundo según la política de Nominatim, y caché persistente en la tabla GeocodeCache para que cada dirección sólo se pida una vez. Devuelve null si falla para que el llamante decida (evita romper el flujo si la red falla). - lib/format.ts: helpers de formato es-ES (fechas, horas, distancias, duraciones, etiquetas legibles de estados de Order/Route/Stop). Estos clientes son la única superficie del sistema que habla con el exterior, lo que facilita auditarlos y eventualmente cambiarlos (p. ej. auto-hospedar OSRM/Nominatim para no depender del servicio público).
Endpoints REST en Next.js App Router con validación zod en todos los
inputs y guard de sesión vía getSession(). Operaciones:
- /api/orders
- GET: lista con filtros por status, date (YYYY-MM-DD) y q (búsqueda
libre en code, street y customer.name). Incluye customer y routeStop.
- POST: crea pedido + customer si no existe + dispara geocoding contra
Nominatim. El código se autogenera ORD-YYYY-NNNNN.
- /api/orders/[id] - GET / PATCH / DELETE (solo ADMIN). PATCH re-geocodifica
si cambia dirección y trata el id como id o como code.
- /api/vehicles - GET con filtro ?available=true.
- /api/users - GET con filtro ?role= (útil para listar conductores).
- /api/incidents - GET / POST. La incidencia queda asociada a pedido y/o
ruta y registra al usuario que la reportó.
Todos los endpoints devuelven 401 sin sesión, 400 si zod falla, y 404 si
el recurso no existe. Mensajes de error en español.
…oding Primera pantalla de la app (/orders), enfocada al despachador. Componentes: - OrdersTable: tabla shadcn con búsqueda libre (código, cliente, calle), filtro por estado (PENDING, DISPATCHED, IN_TRANSIT, DELIVERED, FAILED, RESCHEDULED), contador de resultados y formato es-ES de fechas/horas. Marca visualmente si el pedido tiene coordenadas geocodificadas o no. - OrderStatusBadge: badge con paleta diferenciada por estado. - OrderFormDialog: diálogo de creación con campos cliente / dirección / franja horaria / peso / notas. Si la dirección no existía en GeocodeCache se geocodifica vía Nominatim en el momento del POST y se muestra toast con confirmación de éxito + indicador de si se geocodificó. - page.tsx: server component que carga los pedidos con Prisma desde DB y los pasa serializados al componente cliente. force-dynamic para reflejar cambios en tiempo real al volver de otras pantallas. La tabla está limitada a 500 pedidos por carga (suficiente para PYMEs) sin paginación todavía: optimización para fases posteriores cuando la escala lo requiera.
… averías
Núcleo lógico de la optimización de rutas. Combina OSRM /trip (resuelve TSP)
con filtros de sector y restricciones de ventana horaria para producir
soluciones útiles sin necesidad de OR-Tools embebido.
lib/optimize.ts:
- optimizeOption(date, sector, ...): selecciona pedidos PENDING/DISPATCHED
del día filtrados por sector geográfico, los manda a OSRM con depósito
como source, y construye paradas con ETA acumulada (servicio + travel).
Marca withinWindow=false si la ETA cae fuera de la franja del cliente.
- suggestRoutes(date): genera hasta 3 opciones legibles
A. Ruta Centro (Centro, Carolinas, Benalúa, Florida)
B. Ruta Playa San Juan (Playa San Juan, Albufereta)
C. Ruta Completa (mezcla de sectores, truncada a 14 stops)
La clasificación es por bounding box de lat/lng - suficiente para
Alicante; en producción usar un GeoJSON de barrios.
- rescheduleRoute(routeId, delayMinutes): RE-OPTIMIZA tras avería.
1. Identifica paradas pendientes (no DELIVERED/FAILED).
2. Punto de partida = última parada entregada o depósito si ninguna.
3. Suma el delay al tiempo actual y vuelve a llamar a OSRM /trip.
4. Para cada parada, si la nueva ETA supera windowEnd se mueve a la
lista de DIFERIDAS (se reprograman a mañana).
Esta función es la que materializa el "wow" de la demo: el chatbot la
llama con "se me ha averiado la furgo, X minutos" y todo se reorganiza.
API:
- POST /api/optimize: proxy fino sobre suggestRoutes (futuro: delegar a
microservicio Python con OR-Tools cuando haya time windows estrictas).
- /api/routes: GET por fecha/conductor/status, POST que persiste una
opción aceptada (crea Route + RouteStops, llama a OSRM /route para
guardar la polyline final, marca furgoneta no disponible, pone Orders
en DISPATCHED).
- /api/routes/[id]: GET con stops y conductor.
Pantalla /routes: listado en tarjetas con resumen visual (entregadas/total,
kms, duración). Las nuevas rutas se crean desde el chatbot.
El centro de comandos del sistema: chatbot conversacional en español que interactúa con el resto de la app vía tool calling sobre un LLM local. Privacidad por diseño - los datos de clientes no salen de la máquina. lib/ollama-client.ts: - Wrapper sobre POST /api/chat de Ollama (puerto 11434). - Configurado con llama3.1:8b por defecto, keep_alive=30m para mantener el modelo en memoria entre turnos, num_ctx=4096, temperatura baja (0.2). - Soporta el campo tools en formato OpenAI-compatible. lib/chat/tools.ts: define 13 herramientas con JSONSchema que el LLM puede invocar: current_time, list_orders, get_order, update_order, list_vehicles, list_drivers, suggest_routes, assign_route, list_routes, get_route, report_incident, reschedule_route, mark_stop_delivered. lib/chat/system-prompt.ts: prompt en español con identidad "OpenRoute Assistant" y reglas de conducta: - Llamar current_time antes de filtrar por "hoy". - Confirmar antes de mutaciones. - Comunicar claramente qué se diferió a mañana tras averías. lib/chat/tool-handlers.ts: implementación de cada tool sobre Prisma + helpers de optimize. Devuelve datos condensados al LLM (no documentos completos) para mantener el prompt corto. Mantiene un mapa lastSuggestions por sessionId para que assign_route pueda recuperar las opciones devueltas por suggest_routes (cache en memoria del proceso). lib/chat/runner.ts: loop tool-calling con tope de 5 iteraciones. Carga historial de la sesión (últimos 24 mensajes), envía a Ollama, ejecuta tool calls, persiste cada paso (ChatMessage role=user/assistant/tool con toolCalls JSON y toolName). Si Ollama falla devuelve el error como mensaje del asistente sin romper. lib/chat/parse-tool-calls.ts: parser tolerante para cuando llama3.1:8b emite tool calls como JSON inline en el texto en lugar de usar el campo estructurado tool_calls (fallo conocido del modelo). Extrae los JSON con escaneo brace-balanced y los convierte en ToolCall sintéticos. Repara también referencias a variables sin comillas como current_time. API /api/chat: - POST: ejecuta el runner. Crea ChatSession nueva si no se pasa sessionId existente. Devuelve los nuevos mensajes + uiHints para que la UI muestre links a rutas creadas. - GET sin sessionId: lista las últimas 10 sesiones del usuario. - GET con sessionId: historial completo de mensajes. El sistema es completamente offline (con Ollama local + OSRM cacheado), preservando privacidad de los datos del cliente.
Pantalla /chat - el centro de comandos del sistema desde la perspectiva
del usuario.
components/chat/ChatWindow.tsx (client component):
- Estado local de mensajes que se sincroniza con la sesión persistida.
- Auto-scroll al fondo en cada respuesta nueva.
- Pantalla vacía: 4 sugerencias para arrancar conversación
"Necesito rutas para hoy"
"¿Qué pedidos hay pendientes?"
"¿Cuántas rutas se han hecho hoy?"
"Se me ha averiado la furgo, 45 minutos"
- Input: Textarea con Enter para enviar, Shift+Enter para nueva línea.
- Indicador "Pensando..." con spinner mientras el backend ejecuta el
runner (puede tardar 5-20s con llama3.1:8b la primera vez).
- Si una respuesta crea/reasigna una ruta, aparece atajo "Ver ruta XX →"
en la cabecera enlazando a /routes.
- Toast con error si la red o el servidor fallan.
components/chat/MessageBubble.tsx:
- Burbuja distinguida por rol (user / assistant / tool).
- Mensajes tool plegables con <details> mostrando JSON formateado y
marca visual ✓ / ✗ según si la herramienta tuvo éxito. Esto da
transparencia al usuario sobre qué está haciendo el LLM (criterio
de IA explicable / responsable).
El chatbot es accesible solo a usuarios autenticados (protección por
middleware) y cada conversación queda auditada en la DB.
Visualización end-to-end de una ruta planificada. Pantalla /routes/[id]
con dos paneles sincronizados:
components/map/RouteMap.tsx (client-only, dynamic import sin SSR):
- MapContainer Leaflet + tiles OpenStreetMap (atribución correcta).
- Polyline decodificada desde el formato polyline6 que devuelve OSRM,
pintada en verde corporativo #1a531a con weight=5.
- Marcadores numerados (1, 2, 3...) usando divIcon con CSS custom
(gota invertida con número dentro). Color por StopStatus:
azul = PENDING, verde = DELIVERED, rojo = FAILED/SKIPPED, ámbar = SELECTED.
- Marcador especial cuadrado para el depósito con icono 🏭.
- FitBounds automático en montaje + FlyTo cuando se selecciona una
parada desde el panel lateral.
components/routes/RouteDetailClient.tsx:
- Cabecera con código de ruta, conductor, furgoneta, distancia, duración,
contador entregadas/total y badge de estado.
- Panel lateral derecho con lista de paradas en orden óptimo: secuencia,
cliente, dirección, código de pedido, ETA planificada, ventana del
cliente, notas. Botón "Marcar entregada" en las paradas PENDING.
- Selección sincronizada: clic en parada centra el mapa con flyTo,
clic en marcador selecciona la parada en el panel.
- Sugerencia inline para usar el chatbot si surge una incidencia.
API /api/routes/[id]/stops/[stopId] PATCH:
- Marca la parada como ARRIVED / DELIVERED / FAILED / SKIPPED.
- Cascada al Order asociado (DELIVERED → status DELIVERED, etc.).
Leaflet se importa dinámicamente con ssr:false para evitar errores de
window en Server Components, y su CSS se incluye desde globals.css.
Documentación de proyecto que refleja la nueva estructura coexistente backend Python + frontend Next.js. Pensada para que cualquier tercero pueda entender, ejecutar y extender el sistema (criterio de "diseño para la reutilización" del scoring de código abierto). README.md (ampliado, conservando el contenido original del equipo): - Sección "Dos componentes complementarios" que aclara la separación. - Instalación dividida en backend Python (Streamlit + OR-Tools) y frontend web/ (Next.js + Ollama + OSRM + Leaflet). - Tabla de usuarios demo del frontend. - Guión de demo end-to-end de 5 minutos del frontend. - Hoja de ruta resumida + enlace a ROADMAP.md. - Sección de contribuciones + enlace a CONTRIBUTING.md. - "Built with": agradecimientos a todas las dependencias open source con sus licencias, separadas por componente. - Badge de licencia actualizado a Apache 2.0. - Nombre unificado a "OpenRoute" en lugar de "OpenRoutePyME". docs/ARCHITECTURE.md (nuevo): - Diagrama ASCII de cada componente. - Decisiones técnicas con su contexto: por qué Ollama local, por qué SQLite, por qué Next.js 14 App Router, etc. - Modelo de datos completo con explicaciones. - Estructura de carpetas de web/ con propósito de cada archivo. - Documentación del sistema de tool calling y los 13 tools del chatbot. - Flujo end-to-end del "wow" de la demo (auto-gestión de averías). - Sección "Decisiones que no escalan" con la deuda técnica conocida. - Hoja de ruta de integración Python ↔ web/. docs/ROADMAP.md (nuevo): - Estado actual separado por componente. - Corto plazo (1-2 meses): integración, tests, CI/CD, Docker, Postgres. - Medio plazo (3-6 meses): ficha técnica conductor, app móvil PWA, notificaciones cliente, vista despachador en tiempo real. - Largo plazo (6-12 meses): multi-tenant, integración ERPs/ecommerce, i18n. - Mejoras transversales: tests, accesibilidad, docs, observabilidad.
…ense Dos cambios necesarios para que el build de producción pase limpio (sin warnings de ESLint ni errores de prerender): - RouteMap.tsx: eliminar import useRef no usado. - tool-handlers.ts: eliminar import osrmRoute no usado. - optimize.ts: eliminar import osrmRoute no usado. - login/page.tsx: extraer el componente que usa useSearchParams a un child LoginForm y envolverlo en <Suspense>. Sin esto Next.js 14 falla en build con "useSearchParams() should be wrapped in a suspense boundary" porque /login se prerendera estáticamente. Verificado en local: - npm run lint → ✓ No ESLint warnings or errors - npx tsc --noEmit → sin errores - npm run build → ✓ Compiled successfully Este fix prepara el terreno para el workflow de CI del siguiente commit.
…rontend
Workflow .github/workflows/web-ci.yml que se dispara en:
- Cada Pull Request que toque web/** o el propio workflow.
- Cada push a main que afecte a web/**.
El job lint-typecheck-build corre en ubuntu-latest e incluye:
1. Setup de Node.js 20 con caché de npm vía package-lock.
2. npm ci (instalación reproducible).
3. npx prisma generate (los tipos del cliente Prisma son necesarios
para el type-check).
4. npm run lint (ESLint reglas Next.js).
5. npx tsc --noEmit (validación de tipos sin emitir JS).
6. npm run build (build de producción de Next.js).
El build recibe envs dummy via env: para que no falle por falta de
DATABASE_URL/JWT_SECRET. En producción real estos vienen de secrets.
Beneficios del CI para el proyecto:
- Bloquea PRs que rompan el build antes del merge.
- Visibilidad de calidad: badge verde/rojo junto a cada commit del PR.
- Refuerza la "seguridad por diseño" y "diseño para la reutilización"
del criterio de código abierto del hackathon (25% del scoring).
Tiempo estimado del workflow: ~3 minutos.
Coste: gratis en repos públicos.
El backend Python tendrá su propio workflow en una iteración posterior
(py-ci.yml con ruff + pytest), una vez la suite del backend madure.
…onfusa Los componentes Dialog y Select de shadcn usaban variables CSS de fondo (bg-background, bg-popover, bg-accent) que dependían de los tokens oklch de globals.css. En el navegador del usuario no se renderizaban bien y los modales/dropdowns aparecían translúcidos, dejando ver las tablas y listados de detrás superpuestos al contenido (texto sobre texto). Cambios: - Dialog overlay: bg-black/80 → bg-slate-900/70 con backdrop-blur-sm. Más uniforme y con efecto blur sutil que mejora la jerarquía visual. - Dialog content: bg-background → bg-white sólido (dark:bg-slate-900). Borde explícito border-slate-200 y shadow-2xl en lugar de shadow-lg para que destaque más sobre el overlay. - Select content: bg-popover → bg-white sólido (dark:bg-slate-900) con border-slate-200 y shadow-lg. - Select item: focus:bg-accent → hover:bg-slate-100 focus:bg-slate-100. Ahora el hover funciona en lugar de solo el focus. Reportado por el usuario tras prueba del módulo "Nuevo pedido" y filtro de estados en /orders.
El modelo llama3.1:8b envía con frecuencia los argumentos numéricos como
strings ("20" en lugar de 20), provocando un error de Prisma al intentar
guardar en el campo Int de Incident.durationMin o al calcular el offset
del reschedule. El bot lo manifestaba como una respuesta confusa al
usuario en lugar de actuar.
Cambios en tool-handlers.ts:
- Nuevo helper toNumber(value) que acepta number, string numérico, o
incluso strings con unidades ("20 minutos" → 20) y devuelve undefined
si no es coercible. Mantiene null seguro frente a Prisma.
- suggest_routes: maxStops → toNumber(args.maxStops) ?? 10.
- report_incident: durationMin → toNumber(args.durationMin) ?? null.
- reschedule_route: delayMinutes → toNumber + validación explícita con
mensaje de error claro ("debe ser un número de minutos") si falla.
Cambios en system-prompt.ts:
- Nueva sección "FORMATO DE ARGUMENTOS (IMPORTANTE)" que instruye al
modelo a enviar los numéricos como números, no strings, con ejemplo
correcto vs incorrecto explícito.
- Indica también qué campos son strings (códigos, fechas) y cuáles son
numéricos, para reducir alucinaciones.
Esto debería resolver el caso reportado por el usuario donde "20
minutos de avería" provocaba un error en Prisma sobre Int|Null.
…ipal Antes, el layout del dashboard usaba min-h-screen y el main con overflow-auto, lo que en /orders y /routes hacía que el scroll de la tabla/lista arrastrase a toda la página, haciendo que el sidebar "subiera" cuando el usuario bajaba en la tabla. Cambios: - DashboardLayout: min-h-screen → h-screen overflow-hidden en el div contenedor. Así el viewport del shell queda fijo y el desbordamiento vertical lo absorbe únicamente el <main>. - <main>: overflow-auto → overflow-y-auto overflow-x-hidden. Sólo el área de contenido scrollea verticalmente, sin arrastrar el sidebar. El overflow-x-hidden evita scroll horizontal accidental por componentes anchos. - Sidebar: añadir h-full para ocupar toda la altura del shell de forma consistente (importante cuando hay poco contenido en una pantalla como /routes vacía). Resultado: el sidebar queda visualmente "anclado" a la izquierda en todas las pantallas, sin saltar al hacer scroll.
Reemplaza el login básico (card centrada sobre gradient verde) por un layout de dos columnas tipo SaaS moderno, alineado con estándares de producto B2B. Lado izquierdo (oculto en móvil, 50% en lg+): - Gradient diagonal con los tonos corporativos (#0d2f0d → #1a531a → #134013). - Patrón decorativo sutil de puntos con baja opacidad. - Logo blanco (nueva variante public/logo-white.svg) sobre fondo semitransparente con backdrop blur, en lugar del logo verde sobre caja blanca que se veía descontextualizado. - Tagline grande "Tu flota, optimizada con IA local" + sub-descripción del producto. - Lista de 3 features clave del sistema (chatbot LLM local, optimización VRP, auto-gestión averías) con iconos lucide. - Footer pequeño con la atribución al hackathon. Lado derecho (formulario): - Fondo blanco limpio. - Heading "Bienvenido de vuelta" + subtítulo claro. - Inputs con altura h-11 (más cómodos al click) e iconos User/Lock embebidos a la izquierda. - Botón "Entrar" más grande y con sombra. - Sección de usuarios demo colapsable: por defecto cerrada para no abrumar; al expandir muestra 5 cards (admin, despacho, juan, maria, carlos) clickables que autorellenan el formulario. - Mensaje de error con icono AlertCircle dentro de un panel rojo claro con borde, en lugar del texto rojo plano de antes. Responsive: en pantallas <lg solo se ve el formulario, con una marca pequeña de OpenRoute en la esquina superior izquierda. Mantiene el <Suspense> sobre el componente que usa useSearchParams para que el build de producción de Next.js 14 prerendere /login estáticamente sin errores. Reportado por el usuario tras revisar la pantalla de login.
Collaborator
|
A tope ! |
juandmg020407
added a commit
that referenced
this pull request
May 26, 2026
…IA local Integra el backend de optimización completo de OpenRoute en main, sumándose al frontend conversacional del PR #3 para completar el sistema end-to-end. CONTENIDO INTEGRADO Motor VRP (src/): - optimizer.py — solver dual con patrón Strategy: heurística propia (K-Means + Vecino Más Cercano Ponderado) y Google OR-Tools (CVRPTW industrial) con fallback automático. - data_processor.py — limpieza, validación y matrices Haversine ajustadas ×1.3 para reflejar el callejero urbano. - metrics.py — simulador baseline manual con 3 heurísticas humanas + cálculo de matriz comparativa de ahorros. - ai_assistant.py — generador de informes en lenguaje natural con Ollama local (mismo modelo que el frontend) + fallback de plantillas heurísticas que calculan recomendaciones dinámicamente a partir de los datos reales de la flota. - test_optimizer.py, test_run.py — suite de pruebas unitarias y test end-to-end con reporte comparativo. Datos (data/): - pedidos_ejemplo.csv — 30 pedidos reales en Elche y Alicante con coordenadas precisas, prioridades, pesos y ventanas horarias. - vehiculos_config.json — flota de 3 furgonetas (eléctrica, diésel, apoyo) con capacidades y costes por kilómetro. Módulos reutilizables (skills/): - 1_data_cleaning/, 2_eda/, 3_models/ — scripts académicos modularizados para reutilización en otros proyectos. Documentación: - docs/BACKEND_INTEGRATION.md — guía técnica en 3 pasos para consumir el motor desde Streamlit, FastAPI o cualquier app Python. Dependencias: - requirements.txt actualizado con numpy, ortools y requests, además de las ya existentes (streamlit, pandas, folium, streamlit-folium). IMPACTO MEDIDO (30 pedidos, 3 furgonetas, baseline manual vs OpenRoute) Distancia: 373.51 km → 172.39 km (-53.8%) Coste: 88.39 € → 44.94 € (-49.2%) CO2: 82.17 kg → 37.93 kg (-53.8%) Tiempo: 25.12 h → 18.45 h (-26.6%) Sobrecargas: 3 → 2 (un incidente físico evitado) NOTAS DEL PROCESO La rama original feature/openroute-backend se creó con historia git independiente, lo que impedía a GitHub generar el PR estándar. Para preservar todos los commits originales con su atribución, se merge mediante una rama intermedia feat/backend-optimization derivada de main con --allow-unrelated-histories. Los 8 commits de Samuel aparecen en el historial con su nombre como autor. Tres commits adicionales aplicados antes del merge: - f27fa5f — migración del AIAssistant de Gemini API a Ollama local (coherencia con frontend e "IA Responsable y Abierta") + fix de plantilla de respaldo (referencia personal eliminada, valores hardcodeados sustituidos por cálculo dinámico). - dd8d34e — README personal del autor movido a la guía técnica docs/BACKEND_INTEGRATION.md para evitar conflicto con el README del frontend. - 65dbcbd — eliminados .cloudecode_rules (config personal del IDE del autor) y carpeta OpenRoute/ (PDFs de SEDIA con copyright de la organización + docs internos del equipo, accesibles aún en el historial git). ESTADO RESULTANTE DEL REPO main ahora contiene el producto OpenRoute completo: - Frontend Next.js + chatbot LLM en web/ (PR #3). - Backend Python VRP + IA local en src/, data/, skills/. - Documentación unificada en docs/. - Un único README ampliado en raíz que cubre ambos componentes. Co-authored-by: Samuel Parra <parrasamuel453@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resumen
Añade el frontend conversacional del proyecto (
web/) como segundo componente coexistente con el backend Python de optimización ya existente. La filosofía es que el LLM local sea la interfaz principal de operación.El backend Python con OR-Tools, Streamlit, etc. no se toca. Ambos componentes pueden ejecutarse independientemente; la integración HTTP entre ellos queda como evolución natural (descrita en el roadmap).
Qué incluye
llama3.1:8blocal · JWT en cookie httpOnly./login,/orders,/chat,/routes,/routes/[id].llama3.1:8bemite tool calls como JSON inline en lugar del campo estructurado (fallo conocido del modelo).Estructura de commits
13 commits granulares siguiendo Conventional Commits:
chore: añadir CONTRIBUTING y CODE_OF_CONDUCTchore: extender .gitignore con reglas para Node, Next.js y SQLitefeat(web): scaffold Next.js 14 con TypeScript, Tailwind y shadcn/uifeat(web): añadir esquema Prisma con SQLite y seed de 47 pedidos en Alicantefeat(web): autenticación JWT en cookie httpOnly y pantalla de loginfeat(web): clientes OSRM y Nominatim con caché + helpers de formatofeat(web): API routes de pedidos, vehículos, usuarios e incidenciasfeat(web): pantalla de pedidos con tabla, filtros y creación con geocodingfeat(web): optimizador VRP con 3 opciones por sector y reschedule por averíasfeat(web): cliente Ollama, sistema de tools del chatbot y runnerfeat(web): UI del chatbot con sugerencias, burbujas y cards de toolsfeat(web): pantalla de mapa Leaflet con polyline real y panel de paradasdocs: ARCHITECTURE, ROADMAP y README ampliado con frontend web/Cómo probarlo
Requisitos: Node 20+, Ollama instalado, ~5GB libres.
ollama pull llama3.1:8b cd web cp .env.example .env npm install npx prisma migrate dev npm run db:seed npm run devAbre http://localhost:3000 e inicia con
admin / admin123.Guion de demo (5 min):
/orders→ tabla con 47 pedidos de Alicante./chat→ "Sugiere rutas para hoy" → 3 opciones (Centro, Playa, Completa).RT-2026-XX-XX-A./routes/[id]→ mapa Leaflet con polyline real por calles + 6-10 marcadores numerados.Decisiones técnicas relevantes
/trip). Para casos VRP con time windows estrictas o >15 paradas, el roadmap contempla llamar al backend Python como microservicio.react-leaflet@4.2.1(no v5) porque v5 requiere React 19 y aquí va con React 18.prisma.config.tsque evitamos.Notas para revisores
app/,data/,optimizar_rutas.py,requirements.txt, ni los scripts enskills/.CONTRIBUTING.mdyCODE_OF_CONDUCT.mdse añaden en raíz y cubren contribuciones a ambos componentes.docs/ARCHITECTURE.mdydocs/ROADMAP.md.📸 Capturas de pantalla
Mapa de ruta optimizada
Ruta
RT-2026-05-25-Aplanificada por el chatbot y asignada a María (furgo 5678-DEF). Polyline real por calles de Alicante calculada vía OSRM, 10 marcadores numerados en orden óptimo del TSP, depósito como icono cuadrado oscuro. Panel lateral con ETAs y franjas horarias del cliente.Centro de comandos (chatbot)
El chatbot LLM local actúa como UI principal del sistema. Identificado como
OpenRoute Assistant · llama3.1:8b · tool calling local. Sugerencias predefinidas para arrancar conversación en español natural.Sugerencia de Rutas
El administrador solicita rutas para hoy en lenguaje natural y el sistema reorganiza la ruta automáticamente: reoptimiza las paradas pendientes con OSRM, mueve a mañana las que ya no caben en su franja, registra una incidencia y comunica las nuevas ETAs. La tarjeta plegable ⚙️ reschedule_route ✓ muestra el JSON del resultado para auditoría y transparencia.
Base de datos de pedidos
47 pedidos sembrados en 14 barrios reales de Alicante (Centro, Playa San Juan, Albufereta, Vistahermosa, San Blas, Carolinas, Benalúa, Garbinet, Babel, Florida, Pla). Tabla con filtro por estado, búsqueda libre, badges semánticos y formato es-ES de fechas.
Listado de rutas planificadas
Vista resumen con métricas (kms, duración, % entregadas). Las nuevas rutas se crean desde el chatbot, esta pantalla es solo lectura.
cc: @echeguate @giulianpeter