An end-to-end lead scoring and assignment demo pipeline built with FastAPI, scikit-learn, OR-Tools, and Streamlit.
This repository contains a synthetic lead scoring demo that can be wired into Salesforce via Apex triggers and scheduled export jobs.
Key features:
- Synthetic lead generation with a latent quality signal
- Gradient Boosting model training and inference
- Sales assignment optimizer with seniority routing and industry quotas
- Email reply intent scoring using a DeBERTa MNLI cross-encoder (
cross-encoder/nli-deberta-v3-small) - Streamlit dashboard for score inspection and assignment visualization
- Dockerized deployment for API, dashboard, and scheduler
app/— FastAPI application and business logicapp/main.py— FastAPI entrypointapp/api/routes/— HTTP route handlersapp/services/— score, optimization, and Salesforce mapping logicapp/email_intelligence/— MNLI analysis loader and helpersapp/schemas/— Pydantic request/response models
config/optimizer.json— team roster, quotas, and assignment settingsdata/simulate.py— synthetic lead generatormodels/train.py— training script formodels/lead_scorer.pkljobs/scheduled_assignment.py— scheduled export workflowstreamlit_app.py— Streamlit dashboarddocker-compose.yml— API, dashboard, and scheduler servicesDockerfile— single image for all servicesdocker-entrypoint.sh— first-run bootstrap for data/model assetsSALESFORCE_INTEGRATION.md— Salesforce setup and Apex integration guideoutput/— generated assignment CSVs (ignored by git)
- Create a virtual environment and install dependencies:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txt- Generate synthetic data:
python data/simulate.py- Train the lead scoring model:
python models/train.pyuvicorn app.main:app --reloadstreamlit run streamlit_app.pypython jobs/scheduled_assignment.pyBuild and start all services:
docker compose up --buildRun in detached mode:
docker compose up --build -dStop services:
docker compose downClean volumes and cache::
docker compose down -vGET /health— health checkPOST /score/lead— score a single leadPOST /score/batch— score multiple leadsPOST /score/optimize— assign leads to sales repsPOST /ingest/score— ingest and score a Salesforce lead payloadPOST /ingest/score/batch— batch ingest and score leadsPOST /ingest/leads— ingest raw leadsPOST /email/analyze— analyze a prospect reply and blend MNLI intent scoreGET /email/benchmark— run the fixed MNLI benchmark suitePOST /export/trigger— trigger assignment exportGET /export/assignments— download assignment CSVsPOST /simulation/verify— kick off a capped Monte Carlo simulation-verification runGET /simulation/verify/{run_id}— poll status / fetch the summary once doneGET /model/metrics— AUC-ROC/PR, Brier, ECE pre/post calibration, confusion matrix, ROC curveGET /model/calibration— reliability-diagram data for the raw and calibrated modelGET /model/feature-importance— impurity-based and permutation feature importancesGET /model/uncertainty— Monte Carlo score distribution for a lead profileGET /figures/simulation/*— Monte Carlo simulation figures (conversion-rate histogram, latent-decile monotonicity, causal graph, MC dashboard, correlation heatmap)GET /figures/model/*— ROC/PR curves, calibration curve, feature-importance chartGET /figures/mnli/confusion-matrix— MNLI benchmark confusion matrixGET /figures/optimizer/*— assignment heatmap, constraint-cost comparisonGET /reports/simulation-validation-table— Monte Carlo validation summary tableGET /reports/email-score-update-cases— representative email score-movement casesGET /reports/optimizer-validation-table— per-salesperson assignment/quota/capacity table
- Synthetic data is intentionally generated from a latent quality variable.
- MNLI scoring is only used on lead replies, not cold leads.
- Reply score blending is always
0.6 * MNLI + 0.4 * model_score. leads.csvis the demo persistence layer; no database is used.- Business logic is implemented in
app/services/, not route handlers. - Seniority routing is enforced by the optimizer and should not be changed without updating all routing logic.
See SALESFORCE_INTEGRATION.md for step-by-step Salesforce setup, Apex trigger code, and integration details.
output/is gitignored and stores generated assignment exports.models/lead_scorer.pklis produced bymodels/train.py.data/leads.csvis generated bydata/simulate.pyand updated by scoring workflows.