Customer Twin: Smart Demand Signals

What Inspired Us

When presented with the Inibsa "Smart Demand Signals" challenge, we realized that modern B2B sales teams don't suffer from a lack of data; they suffer from a lack of clarity. Dashboards are often cluttered with raw metrics or "black-box" machine learning predictions that offer a percentage score without explaining why.

Our inspiration was to build a system that thinks like a seasoned sales manager. We wanted to move away from rigid, deterministic rules and instead build a probabilistic digital twin for every (client, product family) pair. The goal wasn't just to flag an anomaly, but to generate a human-readable narrative and recommend the exact next step.

How We Built It

We structured the project around a Python/FastAPI backend and a React (Vite) + Chart.js frontend, creating a single-screen dashboard optimized for immediate action.

The core of our intelligence lies in our dual-model approach, recognizing that different products behave fundamentally differently:

1. The Commodity Twin

For recurring purchases (like anesthesia), we used a Bayesian approach. We model the underlying purchase rate $\lambda$ with a Gamma prior, and the observed weekly sales Y with a Poisson likelihood: $$ Y \sim \text{Poisson}(\lambda) $$ $$ \lambda \sim \text{Gamma}(\alpha, \beta) $$ This conjugate setup yields a Negative Binomial predictive distribution for future purchases: $$ Y_{new} \mid Y_{obs} \sim \text{NegBin}\left(\alpha + \sum Y_i, \frac{\beta}{\beta+1}\right) $$ This allows us to calculate precise confidence bands (e.g., P5 to P95). If a client's purchases fall below this band, we detect a potential loss.

2. The Technical Twin

For sporadic, variable purchases (like biomaterials), regular weekly bands fail. Instead, we model the Inter-Purchase Time (IPT) using a Log-Normal distribution (with a Weibull fallback for low data): $$ \log(\text{IPT}) \sim \mathcal{N}(\mu, \sigma^2) $$ An alert fires if the silence exceeds the P90 expected time and shows a deteriorating slope.

3. Contextual Bandit Recommender

To route these signals into action, we implemented a Thompson Sampling Contextual Bandit. For every state, the probability of an action yielding a positive commercial outcome is modeled as a Beta distribution: $$ \theta_{a, x} \sim \text{Beta}(\alpha_{a, x}, \beta_{a, x}) $$ When the sales rep clicks "I will act" or "False alarm", the bandit updates its posterior, continuously learning the best approach over time. We also integrated ElevenLabs to generate on-the-go audio briefings from our deterministic text narratives.

Challenges We Faced

  • Unobservable Competition: We never directly see if a client bought from a competitor. Fuga (churn) signals had to be probabilistic inferences rather than certainties. We had to carefully tune our narratives to say "compatible with partial churn" rather than "client has churned."
  • Inconsistent Potential Data: Sometimes a client's actual purchases exceeded their reported maximum potential. We had to implement robust ETL logic to flag potencial_fiable and prevent false "Uncaptured Demand" alerts.
  • The "Cold Start" Problem: Our Contextual Bandit needed historical data to make good recommendations on day one. We solved this by pre-seeding the models with synthetic priors to simulate past interactions, allowing the demo to work flawlessly out of the box.

What We Learned

  • Sophistication $\neq$ Utility: We initially considered complex deep learning sequences, but realized that explainability is paramount in sales. Our Bayesian statistical models proved vastly superior because we could trace exactly why an alert was triggered.
  • Narrative is Everything: A probability score of 0.87 is useless to a busy sales rep. Translating math into a Spanish sentence ("Indicios de fuga parcial en commodities tras 3 semanas fuera de banda") was the most impactful feature we built.
  • Feedback Loops Drive Adoption: By making the "Dismiss" or "Act" buttons directly feed into the Bandit algorithm, we ensure the system aligns with the reality of the sales team over time.

Built With

Share this project:

Updates