Skip to content

GeosData/fuel-intel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fuel-intel

Inteligencia de distribución de combustibles en Colombia. Mide a dónde fluye el volumen despachado por región, producto y proveedor, desde la API abierta de datos.gov.co (SICOM), y entrega un brief de demanda listo para un equipo comercial o de logística.


La necesidad

Un distribuidor mayorista de combustibles vive de una pregunta operativa: ¿hacia qué municipios y qué productos se está moviendo el volumen, y dónde está cambiando la demanda?

El SICOM (Sistema de Información de Combustibles) registra cada despacho mayorista del país: quién despachó, a qué municipio, qué producto y cuánto volumen. Es información pública y se actualiza a diario. Pero está en un portal pensado para consultar registros sueltos, no para leer un mercado. Un equipo comercial que quiera saber "cómo viene el despacho de diésel hacia Córdoba este mes, y si hubo un pico raro" tiene que:

  • bajar registros uno por uno o exportar tablas enormes,
  • sumar volúmenes a mano por municipio y por producto,
  • comparar contra el mes anterior en una hoja de cálculo,
  • y repetirlo cada semana porque la data se mueve todos los días.

Es trabajo manual sobre 6,5 millones de registros. Se hace tarde y se hace mal. El resultado: el distribuidor reacciona a los cambios de demanda en vez de anticiparlos, y no detecta un despacho anómalo hasta que ya pasó. El dolor no es la falta de datos. Es que el volumen crudo no es una lectura de demanda.

Por qué esta solución

La data ya existe, es pública y se actualiza a diario. Lo que falta es la capa que la convierte en una lectura accionable de demanda. Por eso fuel-intel no es otra base de datos ni otro dashboard genérico: es un agente de lectura que toma la pregunta del comercial (destino, producto, fecha) y devuelve los volúmenes que importan más un brief en lenguaje natural.

Decisiones que definen el alcance:

  • No reemplazamos al SICOM, lo leemos. Consumimos su API, no copiamos su data. La fuente sigue siendo la oficial.
  • Volumen primero, narrativa después. El valor para el comercial son los números correctos. La prosa solo los explica.
  • CLI antes que UI. El primer usuario corre esto en su terminal o en un cron a las 7am. Una interfaz web es peso muerto hasta validar que el brief sirve.

Por qué esta arquitectura

El diseño responde a un riesgo concreto: un brief de demanda con un número inventado es peor que no tener brief. Si el equipo mueve inventario o logística sobre un volumen alucinado, pierde plata. Toda la arquitectura se ordena alrededor de evitar eso.

SICOM API (SODA)  →  client  →  models  →  analytics  →  brief  →  CLI
 datos.gov.co      consulta    tipado     volúmenes    narra     entrega
                               y limpia   (código)     (LLM)

Separación dura entre el número y la palabra. Los volúmenes (total, promedio, mediana, destino dominante, producto dominante, despachos atípicos) se calculan en analytics.py, código determinista y testeado. El LLM en brief.py recibe esas cifras ya calculadas y tiene una sola tarea: redactarlas. La regla está en el prompt y en el diseño: usa solo los números que te paso, no inventes ninguna cifra. El LLM narra, no calcula. Así una alucinación no puede cambiar un volumen.

El LLM es opcional. Sin OPENAI_API_KEY el comando funciona igual y entrega las cifras en plantilla. La inteligencia base es determinista; la IA es una capa de comodidad, no el núcleo. Esto también hace el CI verde sin secretos.

El prompt vive en un archivo de texto, no en el código. prompts/brief_es.txt se edita sin tocar Python, y FUEL_BRIEF_PROMPT_PATH permite apuntar a otro. El comportamiento del narrador es un parámetro, no una constante compilada.

Por capas pequeñas y aburridas. client solo habla con la API. models solo tipa y limpia la fila cruda (el volumen viene como string). analytics solo calcula sobre objetos limpios, sin red, por eso se testea en milisegundos. Cada pieza se entiende y se reemplaza sola.

Trade-offs asumidos

  • Snapshot, no streaming. Cada corrida es una foto del momento. Para alertas se programa el comando watch en cron; no montamos infraestructura de eventos para un primer usuario.
  • Detección de atípicos simple (z-score). Un despacho con volumen muy por encima del promedio se marca. No es detección de fraude, es una señal para mirar. Suficiente para un brief, honesto sobre lo que es.
  • Volumen en las unidades del SICOM. No convertimos ni asumimos galones contra litros: reportamos el volumen tal como lo publica la fuente. Honesto sobre lo que es; quien conoce su producto sabe leer la unidad.
  • Filtro por texto sobre la API. Filtramos con like sobre departamento/producto/municipio_proveedor. La data viene en mayúscula y sin tildes ("CORDOBA"), y upper() de SoQL no quita diacríticos; por eso normalizamos la entrada del usuario quitándole tildes antes de comparar. No prometemos exactitud perfecta sobre data sucia ajena.

Instalación

pip install -e ".[dev]"

Uso

# Brief de despachos hacia un departamento
fuel-intel brief --departamento Córdoba --producto diesel --since 2026-05-01

# Despachos desde un proveedor específico
fuel-intel brief --origen Cartagena --limit 500

# Despachos nuevos desde una fecha (para cron)
fuel-intel watch 2026-06-01 --departamento Córdoba

El brief usa OPENAI_API_KEY si está presente; sin ella, entrega las cifras en plantilla. Para narrar con otro prompt: edita prompts/brief_es.txt o exporta FUEL_BRIEF_PROMPT_PATH.

Stack

Python 3.12 · httpx · Pydantic v2 · typer + rich · pytest · ruff · GitHub Actions. Los tests son deterministas y no tocan la red.

Fuente

Distribuidores Mayoristas: despacho de combustibles líquidos (SICOM) — datos.gov.co (Socrata Open Data API). ~6,5M registros, actualización diaria.

Autor

Jotive · dev.jotive.com.co

About

No description or website provided.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages