Files
fn_registry/python/functions/pipelines/run_sales_forecast.md
T
egutierrez 5a4f82cf76 chore: auto-commit (26 archivos)
- python/functions/bigquery/bq_auth.md
- python/functions/bigquery/bq_load_from_file.md
- python/functions/bigquery/bq_load_from_gcs.md
- python/functions/bigquery/client.py
- python/functions/bigquery/queries.py
- python/functions/datascience/__init__.py
- python/functions/datascience/decode_qr_image.py
- python/functions/datascience/load_bq_table_to_duckdb.md
- python/functions/datascience/load_bq_table_to_duckdb.py
- python/functions/pipelines/profile_bq_table.md
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-02 19:00:13 +02:00

6.1 KiB

name, kind, lang, domain, purity, version, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path, params, output
name kind lang domain purity version signature description tags uses_functions uses_types returns returns_optional error_type imports tested tests test_file_path file_path params output
run_sales_forecast pipeline py pipelines impure 1.1.0 def run_sales_forecast(as_of: str = '', horizon: int = 7, model: str = 'baseline_v1', author: str = 'egutierrez', dry_run: bool = False) -> dict Forecast diario de ventas Aurgi (dia x centro x subcategoria CGQ) escrito en BigQuery autingo-159109.sales_forecast.predictions, en una sola llamada. Compone funciones del registry: bq_auth(drop_quota_project=True) para el cliente sin quota project ajeno, bq_query para leer la historia agregada del mart bi_ventas_mart.base_margenes_aa (18 semanas, venta_n saneado) y ejecutar el DELETE de idempotencia, forecast_seasonal_median (modelo PURO mediana estacional + tendencia acotada) para generar todas las predicciones, y bq_load_from_file para cargar el JSONL a la tabla de predicciones. Historia utilizable hasta as_of-1 (el dia as_of esta parcial cuando corre el cron a las 21:00); predice as_of+1..as_of+horizon; run_date=as_of. Solo predice series activas (venta>0 en las ultimas 8 semanas). Idempotente por (run_date, model, author). --dry-run no escribe.
forecast
bigquery
sales
aurgi
pipeline
launcher
forecast_seasonal_median_py_datascience
bq_auth_py_infra
bq_query_py_infra
bq_load_from_file_py_infra
false error_go_core
google-cloud-bigquery
false
python/functions/pipelines/run_sales_forecast.py
name desc
as_of fecha de corte 'YYYY-MM-DD' (dia de la corrida). Vacio (DEFAULT) = hoy. La historia utilizable llega hasta as_of-1 dia (el dia as_of esta parcial en el cron 21:00); se predice as_of+1..as_of+horizon; run_date=as_of
name desc
horizon numero de dias futuros a predecir a partir de as_of+1. Default 7
name desc
model etiqueta del modelo escrita en la columna model de cada fila. Default 'baseline_v1'. Forma parte de la clave de idempotencia
name desc
author autor de la corrida (columna author). Default 'egutierrez'. Forma parte de la clave de idempotencia
name desc
dry_run si True no escribe en BigQuery (ni DELETE ni load): devuelve el resumen + una muestra de 5 filas. Default False
dict dict-no-throw. En exito {status:'ok', run_date, series:N (series activas), rows:N (filas predichas), model, author, rows_loaded, job_id}; con dry_run=True incluye sample:[5 filas] y omite rows_loaded/job_id. En error {status:'error', error, stage}. Por stdout imprime el JSON del resumen; exit 0 si ok, 1 si error

Ejemplo

# Corrida real (cron 21:00): predice los 7 dias siguientes a hoy y carga a BigQuery.
./fn run run_sales_forecast

# Fecha de corte y horizonte explicitos, sin escribir (revisar la muestra):
./fn run run_sales_forecast --as-of 2026-07-01 --horizon 7 --dry-run

# Modelo alternativo (clave de idempotencia distinta: no pisa baseline_v1):
./fn run run_sales_forecast --model baseline_v2 --author egutierrez
# Uso programatico (venv del proyecto, PYTHONPATH=python/functions):
from pipelines.run_sales_forecast import run_sales_forecast

r = run_sales_forecast(as_of="2026-07-01", horizon=7, dry_run=True)
print(r["series"], "series activas,", r["rows"], "filas")
for row in r["sample"]:
    print(row["forecast_date"], row["center_id"], row["subcat_cgq"], row["y_pred"])

Cuando usarla

Cuando quieras (re)generar el forecast diario de ventas Aurgi por centro y subcategoria CGQ y dejarlo en autingo-159109.sales_forecast.predictions en una sola llamada. Es el pipeline que dispara el cron nocturno (21:00): lee la historia del mart, aplica el baseline estacional, y carga las predicciones de forma idempotente. Usa --dry-run para inspeccionar la muestra antes de escribir, o para probar tras un cambio en el mart o en el modelo. Cambia --model para probar una variante sin pisar las predicciones del modelo actual (la clave de idempotencia es run_date + model + author).

Gotchas

  • Impura: requiere ADC de BigQuery configurado (gcloud auth application-default login) con acceso a autingo-159109. Usa bq_auth(drop_quota_project=True) para descartar el quota project del ADC del usuario egutierrez y evitar el 403 USER_PROJECT_DENIED (gotcha conocido del repo).
  • Escribe en produccion: en modo real hace DELETE de las predicciones previas de (run_date, model, author) y luego carga (WRITE_APPEND). Es idempotente para esa combinacion: re-ejecutar la misma corrida no duplica. Cambiar model o author crea un conjunto de predicciones paralelo. Usa --dry-run si solo quieres mirar.
  • La tabla sales_forecast.predictions debe existir con schema fijo y con las columnas exactas que emite el pipeline: run_ts (TIMESTAMP), run_date (DATE), forecast_date (DATE), lag_days (INT64), center_id (STRING), center_name (STRING), ambito (STRING), subcat_cgq (STRING), model (STRING), author (STRING), y_pred (FLOAT64). El load usa autodetect=False: los nombres del JSONL deben coincidir con los de la tabla o el load falla.
  • center_id se emite como STRING (str(idCentro)); subcat_cgq toma el valor de la columna subcat_cqq del mart (el nombre difiere entre origen y destino a proposito). center_name/ambito son los ultimos conocidos por serie (fecha maxima).
  • Historia hasta as_of-1: el dia as_of NO entra en la historia (esta parcial en el cron de las 21:00). Si necesitas incluir el dia en curso, pasa --as-of con el dia siguiente.
  • Solo predice series con venta > 0 en las ultimas 8 semanas: las series muertas se omiten (no aparecen en la tabla). series en la salida cuenta las activas.
  • Guarda 18 semanas de historia del mart: cubre la ventana estacional (8 semanas del mismo dia) mas la tendencia (4+4 semanas) con margen. venta_n se filtra ABS < 1e9 para descartar las filas veneno del mart.

Capability growth log

  • v1.1.0 (2026-07-02) — añade paso 9: refresh de sales_forecast.actuals_daily (tabla física de venta real, ventana móvil de 10 días) tras cargar las predicciones; forecast_eval y el dashboard de competición comparan contra ella.