Omnigraph
Graph engine for context assembly. Object-storage native. Agents work with graph data the way engineers work with code: branched, typed, reviewed, merged, audited, and governed.
Estado en vivo del pipeline MLOps: accuracy, cobertura, drift y operación.
Translation pending
DataPython · HTMLGitHub @melo11miguelOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Sistema MLOps para el reto Pulso TransMi: collector, modelos, inferencia y monitoreo
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Sistema que pronostica la demanda de pasajeros de 12 estaciones de TransMilenio a +15, +30, +45 y +60 minutos y opera ese pronóstico en el tiempo: recolecta datos nuevos, entrena y versiona modelos, predice y envía cada ciclo, mide su propio error y decide cuándo reentrenar. Proyecto del curso MLOps (Universidad Externado de Colombia). Contrato de la API: uexternadojz/pulso-transmi · API:Read the full README ↗
Sistema que pronostica la demanda de pasajeros de 12 estaciones de TransMilenio a +15, +30, +45 y +60 minutos y opera ese pronóstico en el tiempo: recolecta datos nuevos, entrena y versiona modelos, predice y envía cada ciclo, mide su propio error y decide cuándo reentrenar.
Proyecto del curso MLOps (Universidad Externado de Colombia). Contrato de la API: uexternadojz/pulso-transmi · API: https://pulso-transmi.72-60-245-2.sslip.io/docs
flowchart LR
API[API Pulso TransMi<br/>stream · ciclo · submissions] -->|observaciones| COL[collector<br/>cada 30 min]
COL -->|upsert + cursor<br/>en 1 transacción| DB[(Supabase<br/>PostgreSQL + Storage)]
DB --> TR[train<br/>validación temporal]
TR -->|artefacto + ficha| REG[registro de modelos<br/>candidate → champion]
REG --> INF[predict<br/>48 targets por ciclo]
API -->|ciclo abierto, targets| INF
INF -->|entrega con Idempotency-Key| API
INF -->|predicciones + recibo| DB
DB --> MON[monitor<br/>accuracy · drift · operación]
MON -->|decisión + evidencia| DB
MON -.retrain.-> TR
| Capa | Dónde vive | Qué garantiza |
|---|---|---|
| Datos | Supabase (observations, context, stations) | Llave (station_id, observed_at): repetir una carga no duplica |
| Collector | src/pulso/ingest.py + función SQL ingest_observations | El cursor solo avanza si el lote se confirmó (misma transacción) |
| Modelos | model_versions + bucket privado models | Versión, corte de datos, commit, features, validación y hash; un solo champion |
| Inferencia | src/pulso/predict.py | Solo datos ≤ data_cutoff; exactamente los targets del ciclo; evidencia antes de enviar |
| Monitoreo | src/pulso/monitor_job.py | Accuracy móvil y acumulada, drift, salud operacional y decisión registrada |
| Automatización | GitHub Actions (.github/workflows/) | Repetible y observable; el estado vive en la base, no en el runner |
Validación temporal (3 semanas consecutivas, orígenes cada hora, métrica oficial
100 × max(0, 1 − WAPE) por estación y promediada):
| Modelo | Accuracy medio |
|---|---|
gbm_residual (champion) | 87,59 % |
ridge_residual (perfil + corrección lineal) | 87,27 % |
profile_only (perfil estacional puro) | 86,78 % |
| mismo instante de la semana pasada | 83,25 % |
| repetir el último valor | 74,42 % |
La demanda es casi puro calendario: el perfil «estación × hora de la semana» explica el 96 % de la varianza y ya roza el techo estimado (~88 %). El modelo aporta +0,8 pts y, sobre todo, robustez ante cambios: en pruebas de estrés con drift sintético amortigua cambios de nivel y tendencia, y reentrenar con solo 2 días de datos nuevos recupera la mayor parte de un cambio de patrón.
Detalle y límites honestos: reports/eda.md ·
reports/backtest.md · reports/drift_stress.md
context (clima/eventos): la API solo lo publica en el corte estático; el modelo no
debe depender de algo que no tendrá al predecir.promote_model en SQL permite rollback.src/pulso/policy.py): persistencia (no un solo periodo difícil),
datos nuevos suficientes, enfriamiento, y primero se corrige la operación antes de culpar al
modelo. Los umbrales se calibraron con el estrés de drift (y una falsa alarma real llevó a umbrales
de nivel propios de cada estación).cycle_id, versión
del modelo y las 48 predicciones, no de GITHUB_RUN_ID. Así, dos ejecuciones que entregan lo
mismo reciben el mismo recibo (HTTP 200) en vez de gastar dos de los tres intentos del ciclo.timeout-minutes: 8) despertando cada 10 min. Medimos que
GitHub descarta la mayoría de las ejecuciones programadas: con cron horario corrieron 6 de
~31, y hubo un hueco de 5 h 16 min sin ningún disparo (19:03 → 00:19 UTC del 22-09), con
Actions reportado como operational. Como la ventana dura 25 min, eso costaba la mayoría de los
ciclos. La solución: el cron sigue en */10 y admite ejecución manual, pero el job espera
dentro de la ventana y cubre 4 horas, entregando cada ciclo que abra. concurrency mantiene
uno vivo y otro en cola para relevarlo. Evidencia de que funciona: el ciclo de las 00:34 lo
capturó una ejecución programada que arrancó a las 00:19 y esperó 16 sondeos; y la cobertura
rolling 24 h pasó de 0,17 a 0,79 en doce horas.pipeline_runs/.src/pulso/ api · supa · ingest · features · model · baselines · backtest · registry
train · predict · monitor · monitor_job · policy · stress · quality
supabase/migrations/ esquema SQL reproducible (0001-0003)
scripts/ download_data.py · eda.py · run_backtests.py · drift_stress.py · practice_submit.py
reports/ análisis exploratorio, backtesting y estrés de drift (con figuras)
tests/ 165 pruebas (sin red: API y Supabase simulados)
.github/workflows/ ci · collect-and-predict · collect-and-monitor · train
docs/runbook.md puesta en marcha, operación y diagnóstico
Ver docs/runbook.md. En resumen: variables en .env (plantilla en
.env.example), Secrets del repositorio (PULSO_API_KEY, SUPABASE_URL,
SUPABASE_SERVICE_ROLE_KEY), ejecutar una vez el workflow «Entrenar candidato» para crear el
champion inicial y definir la variable PIPELINE_ENABLED=true para activar los horarios.
python -m venv .venv && source .venv/bin/activate
python -m pip install -r requirements.txt && python -m pip install -e '.[eda,dev]'
pytest # 165 pruebas, sin red
python scripts/download_data.py # baja el corte inicial a data/ (hash verificado)
python scripts/eda.py # regenera reports/eda.md
python scripts/run_backtests.py # regenera reports/backtest.md (varios minutos)
python scripts/drift_stress.py # regenera reports/drift_stress.md
python scripts/practice_submit.py # simulacro de entrega; --send para enviar
Los datos iniciales (data/*.csv) no se versionan: se descargan de la API
(/v1/downloads/*) y la fuente de verdad es Supabase.
context no se usa; si la API lo libera durante la competencia sería la mejora principal.src/pulso/monitor.py,
reports/drift_stress.md). MLflow está como EXPORTACIÓN, no como registro primario: ver abajo.next_cursor) con datos reales no se pudo comprobar
(el reloj sigue en waiting); el collector relee la última página y tolera un cursor rechazado.El registro de verdad del pipeline es la tabla model_versions en Supabase: ahí se decide la
promoción, de ahí lee el predictor y ahí está la trazabilidad, con verificación de sha256 del
artefacto, linaje por parent_version y un índice único que garantiza un solo champion a la vez.
scripts/mlflow_export.py exporta ese registro a MLflow para tener su interfaz sobre datos
reales del proyecto. No instrumenta el entrenamiento y no inventa ninguna corrida: lee las
versiones ya registradas y las escribe con sus params, métricas y linaje. Conviene decirlo así
cuando se presente, porque es lo que es.
Se eligió exportar en vez de instrumentar por una razón operativa: el pipeline corre en ejecutores efímeros de GitHub Actions, y poner MLflow como registro primario pedía exponer la cadena de conexión de Postgres a Actions y duplicar la fuente de verdad, con el riesgo de que las dos se desincronicen.
MLflow vive en su propio entorno porque requirements.txt fija versiones exactas (un artefacto de
scikit-learn solo carga con la versión con que se entrenó) y MLflow arrastra las suyas:
# Entorno aparte, una sola vez. cryptography 43 porque las versiones nuevas no traen wheel
# para macOS x86_64 y caerían a compilar con Rust.
python3.12 -m venv .venv-mlflow
.venv-mlflow/bin/python -m pip install "cryptography==43.0.3" mlflow
# Exportar e inspeccionar (SUPABASE_URL y SUPABASE_SERVICE_ROLE_KEY en el entorno)
.venv-mlflow/bin/python scripts/mlflow_export.py
.venv-mlflow/bin/mlflow ui --backend-store-uri sqlite:///mlflow.db --port 5055
# y abrir http://127.0.0.1:5055
El puerto va explícito a propósito: en macOS el 5000 por defecto de MLflow lo ocupa el receptor de AirPlay del Centro de Control, que responde 403, así que la interfaz se ve vacía sin que el error sea evidente. Si hace falta liberar el 5000, se apaga en Ajustes del sistema, General, AirDrop y Handoff, Receptor de AirPlay.
El respaldo es sqlite y no archivos porque el Model Registry de MLflow no funciona sobre el almacén de archivos. Volver a correr el script es idempotente: omite las corridas ya exportadas.
Lo que queda en la interfaz: experimento pulso-transmi con una corrida por versión entrenada
(321 al cierre de la ronda: 1 champion, 243 archivadas, 77 rechazadas), cada una con sus params,
sus métricas de validación incluidas las de por horizonte y por estación, y etiquetas con el
commit, la decisión de la puerta y su motivo; más el modelo pulso-transmi-demanda registrado,
con alias champion y el artefacto del champion adjunto.
MIT
ingestion_runsanon/authenticated; solo la
service role (Secrets de Actions) escribe. Ninguna clave se imprime ni se guarda en la base.