La Inspiración: Un Reto de Sostenibilidad y Privacidad
Nuestra inspiración provino directamente de los retos del Hackathon Banorte (RetoSmartCitiesHackMTY.pdf) y HackMTY (hackmty.pdf). El objetivo era claro: conectar los servicios financieros de Banorte con la gestión de recursos de una "Smart City" (agua, luz, gas). Los documentos del reto pedían explícitamente "promover el uso eficiente de recursos urbanos mediante modelos predictivos".
Esto, combinado con tus bocetos de la interfaz de usuario (Boceto.pdf), nos dio un objetivo concreto: una app que no solo pagara servicios, sino que tuviera los botones "Predecir" y "Apartar".
El desafío técnico más grande que nos autoimpusimos fue la privacidad. No queríamos que el historial de gastos de un usuario viajara a un servidor. Para lograrlo, decidimos que todo el modelo de IA debía ejecutarse **100% "on-device" (en el dispositivo).
Cómo lo Construimos: El Laboratorio de IA y la App Nativa
Dividimos el proyecto en dos fases, un enfoque estándar en MLOps (Machine Learning Operations).
Fase 1: El Laboratorio (Python)
Aquí es donde creamos el "cerebro".
- El Modelo Teórico: Abordamos el problema como un pronóstico de series temporales. Para predecir el gasto del próximo mes ($Y_{t+1}$), necesitábamos información histórica.
- Ingeniería de Características: Creamos las variables (features) que alimentan al modelo. Las más importantes fueron:
- Lag-1 ($Gasto_{t-1}$): El gasto del mes inmediatamente anterior.
- Lag-12 ($Gasto_{t-12}$): El gasto del mismo mes, pero del año anterior. Este es crucial para capturar la estacionalidad (ej. gastas más luz en verano por el A/C).
- Entrenamiento: Usamos un modelo de Regresión Lineal Múltiple, implementado en **TensorFlow/Keras. El objetivo de la IA (un optimizador de gradiente descendiente) es encontrar el conjunto de coeficientes ($\beta$) que minimiza el error entre nuestras predicciones y los gastos reales. Buscamos encontrar los $\hat{\beta}$ que resuelven: $$ \hat{\beta} = \underset{\beta}{\arg \min} \sum_{i=1}^{n} (Y_i - \hat{Y_i})^2 $$ Donde la predicción $\hat{Y_i}$ es nuestra ecuación lineal: $$ \hat{Y_i} = \beta_0 + \beta_1 \cdot (Gasto_{i, t-1}) + \beta_2 \cdot (Gasto_{i, t-12}) + \dots + \epsilon $$
- El Puente Matemático: Antes de entrenar, usamos scikit-learn para "normalizar" los datos con un StandardScaler. Este paso es crítico. Almacenamos la media ($\mu$) y la desviación estándar ($\sigma$) de los datos de entrenamiento.
- El Artefacto Final: Convertimos el modelo entrenado (que ahora contiene los coeficientes $\beta$ óptimos) en un archivo **.tflite (TensorFlow Lite), listo para el móvil.
Fase 2: La App (Flutter 📱)
Aquí es donde construimos la "calculadora" que usa el cerebro.
- Framework: Usamos Flutter con Dart para construir una app nativa para Android.
- Base de Datos Privada: Usamos sqflite para crear una base de datos SQLite local en el teléfono. Aquí es donde se guarda el historial de pagos del usuario a medida que los simula.
- El Intérprete de IA: Usamos la biblioteca tflite_flutter para cargar nuestro archivo .tflite desde los assets.
- Replicando la Matemática: Cuando el usuario presiona "Predecir", la app:
- Lee el historial de la base de datos sqflite.
- Crea las mismas características (lag-1, lag-12).
- Aplica el "Puente Matemático" a la inversa: normaliza los nuevos datos usando los valores $\mu$ y $\sigma$ que guardamos de Python (nuestros scalerMean y _scalerScale). $$ X{\text{scaled}} = \frac{X_{\text{original}} - \mu}{\sigma} $$
- Alimenta estos datos escalados al intérprete de TFLite.
- Recibe la predicción y la muestra en la pantalla, junto con el botón "Apartar".
Los Desafíos: El "Infierno de las Dependencias"
La teoría matemática fue directa. La implementación práctica fue una batalla campal contra las dependencias y la configuración.
- Permisos de Windows: El primer muro fue que Flutter necesitaba "Modo Programador" para compilar plugins nativos (como la IA y la DB), un permiso de seguridad del sistema operativo.
- El Error UnmodifiableUint8ListView: Este fue el enemigo principal. La biblioteca tflite_flutter original tiene un bug conocido que choca con las versiones modernas de Dart.
- El Círculo Vicioso de las Versiones:
- Intento 1: Usar tflite_flutter + el parche dependency_overrides: { ffi: '2.1.0' }. Esto falló al principio.
- Intento 2: Cambiar a una biblioteca alternativa, tflite_flutter_plus.
- Intento 3: La versión ^0.0.2 de _plus no se pudo encontrar (version solving failed).
- Intento 4: Bajar a la versión ^0.0.1 de _plus funcionó, pero nos dio un nuevo error de Android: Namespace not specified en build.gradle.
- Intento 5: Arreglamos manualmente el build.gradle de la biblioteca, solo para descubrir que esta versión también tenía el error UnmodifiableUint8ListView. ¡Estaba rota por ambos lados!
- La Solución Final: Tuvimos que darnos cuenta de que la Combinación 1 era la correcta, pero estaba fallando por un problema de caché. El "reinicio nuclear" (borrar pubspec.lock, .dart_tool y correr flutter clean y flutter pub get) fue lo que finalmente forzó a Flutter a aceptar la combinación correcta:
- Biblioteca: tflite_flutter: ^0.10.4
- Parche: dependency_overrides: { ffi: '2.1.0' }
Lo que Aprendimos
- El Modelo es Fácil, el Despliegue es Difícil: El modelo matemático (regresión) fue la parte más fácil. La verdadera batalla fue el despliegue (MLOps) en un entorno móvil.
- La Importancia de la Sincronización: El "puente" matemático (el StandardScaler) debe ser idéntico en Python y Dart. Un decimal incorrecto en $\mu$ o $\sigma$ y toda la predicción falla.
- La Privacidad es Posible: Demostramos que se puede ofrecer una funcionalidad de IA potente (predicción) sin que un solo dato privado del usuario salga de su teléfono.
- La Persistencia es Clave: Los errores de compilación rara vez son culpa de tu lógica; suelen ser problemas de configuración, caché o versiones. flutter clean y borrar pubspec.lock son tus mejores armas.
Built With
- android
- android-studio
- dart
- ffi
- flutter
- gradle
- intl
- keras
- numpy
- pandas
- path
- python
- scikit-learn
- sqflite
- sqlite
- tensorflow
- tensorflow-lite-(.tflite)
- visual-studio-code
- windows-11

Log in or sign up for Devpost to join the conversation.