crazycrazypete/Masters-four-Tab-OpenAI-Canary
Masters Telecom AI Toolkit (FastAPI + React + Tailwind)
One Docker app, multiple tools in one UI:
- Masters Telecom AI Knowledgebase (default): unified chat for router docs/specs, router lifecycle/replacements, POTS replacement Q&A, and Masters AI docs.
- Router Knowledgebase: internal router docs + datasets RAG (hybrid retrieval, citations, and clearly labeled web-assisted fallback).
- Telco Cost Calculator: multi-location inputs, charts, CSV import/export, PDF quote output.
- Routers: paste router models/SKUs to get lifecycle status (EOS/EOL) plus 4G + 5G replacement picks. Can also show antenna picks.
- Master's AI: Q&A over Masters Telecom reference docs (internal + external audience modes).
- POTS Replacement Q&A: Q&A over POTS replacement docs, with a simple preference to recommend OOMA.
- POTS Replacement Intake: a wizard + spreadsheet import that produces an intake ZIP (PDF summary + Excel) and stores the submission on the HF
/datavolume. - Rapid Router: Verizon-rep order intake for routers + rate plans + quantities, with an admin (password) product loader and email submission (PDF + signature PNG).
Key operator docs:
docs/architecture.mddocs/runbook.mddocs/hf_auth0_operator_checklist.md.env.example.codex/README.md
Environment variables
The app will run without an API key for the CSV-based matching in the Routers tool.
To enable AI/Q&A features, set:
OPENAI_API_KEYOPENAI_MODEL(optional, default:gpt-5-mini)
Optional:
TODAY_YYYY_MM_DD(override the date used for lifecycle status, formatYYYY-MM-DD)
Unified knowledgebase / tab cutover flags:
MASTERS_TOOLKIT_TAB_KNOWLEDGEBASE_ENABLED=true(new single-tab default)- Legacy rollback flags (default
false):MASTERS_TOOLKIT_TAB_ROUTER_KNOWLEDGEBASE_ENABLED,MASTERS_TOOLKIT_TAB_ROUTERS_ENABLED,MASTERS_TOOLKIT_TAB_MASTERS_AI_ENABLED,MASTERS_TOOLKIT_TAB_POTS_REPLACEMENT_QA_ENABLED,MASTERS_TOOLKIT_TAB_TELCO_CALCULATOR_ENABLED,MASTERS_TOOLKIT_TAB_POTS_SAVINGS_ESTIMATOR_ENABLED,MASTERS_TOOLKIT_TAB_POTS_REPLACEMENT_INTAKE_ENABLED,MASTERS_TOOLKIT_TAB_RAPID_ROUTER_ENABLED
Data file paths (normally you can ignore these):
EOS_CSV_PATHdefault/app/routers_eos_eol_by_sku.csvDEC_CSV_PATHdefault/app/feb2026routers.csvPARSEC_CATALOG_PATHoptional explicit Parsec catalog path (if unset, app falls back to corpus docs)
Router Knowledgebase corpus paths:
ROUTER_RAG_BOOTSTRAP_ENABLEDdefaulttrueROUTER_RAG_HF_DATASET_REPOdefaultcrazycrazypete/masters-telecom-kb-corpusROUTER_RAG_HF_DATASET_REVISIONdefaultmainROUTER_RAG_HF_DATASET_SUBDIRdefaultcorpus/_RAG_Ready_KB_OrganizedROUTER_RAG_BOOTSTRAP_DIRdefault/data/router_rag_corpus(falls back to/tmp/router_rag_corpus)ROUTER_RAG_DATA_DIRdefault auto-resolved from downloaded corpus (.../_RAG_Ready_KB_Organized)ROUTER_RAG_CHUNKS_PATHdefault<ROUTER_RAG_DATA_DIR>/04_ingestion/rag_ingestion_chunks.jsonlROUTER_RAG_MANIFEST_PATHdefault<ROUTER_RAG_DATA_DIR>/03_manifests/rag_manifest_organized.csvROUTER_RAG_CACHE_DIRdefault/data/router_rag_index(falls back to/tmp/router_rag_index)ROUTER_RAG_EMBED_MODELdefaulttext-embedding-3-smallROUTER_RAG_OPENAI_MODELdefaultgpt-5-mini(falls back toOPENAI_MODELif unset)ROUTER_RAG_TOP_Kdefault8ROUTER_RAG_MIN_SCOREdefault0.18ROUTER_RAG_ENABLE_RERANKdefaulttrueROUTER_RAG_RERANK_HARD_ONLYdefaulttrue(skip rerank for easy/single-fact queries)ROUTER_RAG_RERANK_HARD_MIN_TOKENSdefault16ROUTER_RAG_RERANK_HARD_HINTScomma list of terms that should force rerankROUTER_RAG_RERANK_MODELdefaultcross-encoder/ms-marco-MiniLM-L-6-v2ROUTER_RAG_CITATION_GATE_ENABLEDdefaulttrueROUTER_RAG_CITATION_MIN_SOURCES_SPECSdefault1ROUTER_RAG_CITATION_MIN_SOURCES_COMPAREdefault2ROUTER_RAG_CITATION_MIN_SOURCES_REPLACEMENTdefault1ROUTER_RAG_CITATION_MIN_UNIQUE_DOCS_COMPAREdefault2ROUTER_RAG_WEB_MODE_DEFAULTdefaultfast(fastorextended)ROUTER_RAG_WEB_MODEoptional per-deployment override (fastorextended)ROUTER_RAG_WEB_FAST_TIMEOUT_Sdefault8.0ROUTER_RAG_WEB_EXTENDED_TIMEOUT_Sdefault18.0ROUTER_RAG_WEB_FAST_MAX_TOKENSdefault900ROUTER_RAG_WEB_EXTENDED_MAX_TOKENSdefault1400ROUTER_RAG_WEB_FAST_CONTEXT_SOURCESdefault3ROUTER_RAG_WEB_EXTENDED_CONTEXT_SOURCESdefault6ROUTER_RAG_ALIAS_DICT_PATHdefault<ROUTER_RAG_DATA_DIR>/03_manifests/router_aliases_dynamic.json
Unified KB performance toggles:
UNIFIED_KB_CACHE_ENABLEDdefaulttrueUNIFIED_KB_CACHE_TTL_Sdefault600UNIFIED_KB_CACHE_MAX_ITEMSdefault512UNIFIED_KB_ROUTER_FACT_FAST_PATHdefaulttrue(fast deterministic answers fromfeb2026routers.csvfor common spec asks)UNIFIED_KB_WEB_TIMEOUT_ROUTER_DOCS_Sdefault5.2UNIFIED_KB_WEB_TIMEOUT_MASTERS_Sdefault4.8UNIFIED_KB_WEB_TIMEOUT_POTS_Sdefault4.8UNIFIED_KB_WEB_TIMEOUT_EXTENDED_Sdefault8.0
Canonical corpus note:
_RAG_Ready_KB_Organizedis the canonical deployment corpus (documents + datasets + manifests + ingestion files)._RAG_Ready_KBis legacy staging and should remain untracked.
Router Knowledgebase maintenance scripts:
python3 backend/scripts/router_rag_import_corpus.py --source-dir '/absolute/path/to/new_docs' --data-dir _RAG_Ready_KB_Organized --report-csv docs/reports/rag_import_report.csv --report-md docs/reports/rag_import_report.md- Imports new corpus files into canonical folders using deterministic triage:
- includes authoritative vendor PDFs,
- excludes screenshots / non-ingestible artifacts / known reseller captures,
- dedupes by SHA-256 against existing corpus files,
- applies canonical naming and collision suffixing.
- Writes import summary reports (CSV + Markdown).
- Use
--dry-runfirst to preview include/skip decisions. python3 backend/scripts/router_rag_device_gap_report.py- Audits
feb2026routers.csv+replacement_devices_missing_from_dec2025routers.csvagainstrag_manifest_organized.csv. - Writes:
docs/reports/router_rag_device_doc_gaps.csvdocs/reports/router_rag_device_doc_gaps.mdpython3 backend/scripts/router_rag_rebuild_ingestion.py --data-dir _RAG_Ready_KB_Organized- Rebuilds:
03_manifests/rag_manifest_organized.csv04_ingestion/rag_ingestion_chunks.jsonl04_ingestion/rag_ingestion_chunks.csv04_ingestion/rag_ingestion_file_stats.csv- Use
--dry-runfirst to validate. python3 backend/scripts/router_rag_alias_growth.py --glob 'docs/evals/*.json' --out-json docs/evals/router_alias_growth_latest.json --apply-auto- Mines message/transcript logs for model nicknames and typo variants.
- Writes alias growth report + updates dynamic alias dictionary at:
_RAG_Ready_KB_Organized/03_manifests/router_aliases_dynamic.jsonpython3 backend/scripts/router_rag_eval50.py --with-openai --semantic-grader --out docs/evals/router_rag_eval50_latest.json --md-out docs/evals/router_rag_eval50_latest.md --trend-file docs/evals/router_rag_eval50_trend.json- Runs 50-case regression with rule + semantic scoring.
- Produces latest report + trend history used by nightly CI.
python3 backend/scripts/unified_kb_eval150.py --cases docs/evals/unified_kb_eval150_cases.json --with-openai --semantic-grader --out docs/evals/unified_kb_eval150_latest.json --md-out docs/evals/unified_kb_eval150_latest.md --trend-file docs/evals/unified_kb_eval150_trend.json- Runs the unified 150-case regression across router docs/lifecycle, POTS, and Masters domains.
- Includes rule scoring + optional second-pass semantic grading + latency tracking.
- Semantic grading can be scoped for speed via
--semantic-policy(hard_edge_or_faildefault) and--semantic-timeout-s. - Supports shard runs via
--start-id/--end-id(for example, run 15-case batches). - Nightly workflow:
.github/workflows/unified-kb-nightly-eval.yml. bash backend/scripts/run_unified_kb_eval150_chunks.sh- Enforces OpenAI key precheck, runs the full 150 in 10-case shards, tracks per-question latency, and writes:
docs/evals/shards10/unified_kb_eval150_<start>_<end>.jsondocs/evals/shards10/unified_kb_eval150_<start>_<end>.mddocs/evals/shards10/unified_kb_eval150_shards10_summary.json- Applies default hard web-time budgets during eval via timeout env vars (overridable).
bash backend/scripts/router_rag_intake_pipeline.sh "<source_dir>"- One-command intake for new corpus drops:
- imports/renames/dedupes (
router_rag_import_corpus.py) - rebuilds ingestion artifacts (
router_rag_rebuild_ingestion.py) - runs gap report + smoke checks (
router_rag_device_gap_report.py,router_rag_smoke.py) - writes timestamped reports in
docs/reports/ bash backend/scripts/release_gate.sh- Pre-release gate (local) before push/deploy:
- validates auth/env configuration
- compiles startup-critical modules
- runs Router RAG smoke
- runs unified 150-case eval with semantic grading + strict exit
- enforces latency budgets (
P95_BUDGET_MS,P99_BUDGET_MS)
Index caches (recommended on Hugging Face):
POTS_INDEX_CACHE_DIRdefault/data/pots_indexMASTERS_INDEX_CACHE_DIRdefault/data/masters_index
Hugging Face cache dirs (recommended on Hugging Face):
HF_HOMEdefault/data/hf_cacheTRANSFORMERS_CACHEdefault/data/hf_cache/transformersSENTENCE_TRANSFORMERS_HOMEdefault/data/hf_cache/sentence_transformers
Intake storage (recommended on Hugging Face):
POTS_INTAKE_STORAGE_DIRdefault/data/pots_intake
Rapid Router order intake:
RAPID_ROUTER_STORAGE_DIRdefault/data/rapid_routerRAPID_ROUTER_ADMIN_PASSWORDrequired to enable the admin loader; store it as a hosted secret, not in repo files
Email (Microsoft 365 SMTP recommended):
RAPID_ROUTER_SMTP_HOSTdefaultsmtp.office365.comRAPID_ROUTER_SMTP_PORTdefault587RAPID_ROUTER_SMTP_USERNAME(example:pete@pdinsights.ai)RAPID_ROUTER_SMTP_PASSWORD(mailbox password or app password, depends on tenant policy)RAPID_ROUTER_FROM_EMAILrequired when SMTP/Graph email submission is enabledRAPID_ROUTER_TO_EMAILrequired when SMTP/Graph email submission is enabled
OCR toggles (off by default):
MASTERS_ENABLE_OCR=1POTS_ENABLE_OCR=1
Retrieval tuning:
MASTERS_RAG_MIN_SCOREdefault0.25(minimum retrieval score before refusing)MASTERS_MAX_CHUNKS_PER_DOCdefault4(caps repeated chunks per document in retrieval)
Auth0 (required-auth mode):
AUTH_REQUIRED=trueAUTH0_DOMAIN=your-tenant.us.auth0.comAUTH0_CLIENT_ID=your_spa_client_id(optional Docker fallback for frontend build vars)AUTH0_AUDIENCE=optional. Leave unset unless your Auth0 tenant has a real custom API Identifier for this app.- Do not use
https://masters-toolkit-apiorhttps://masters-toolkit-api/; those legacy placeholder values are ignored by current auth code. AUTH0_ISSUER=https://your-tenant.us.auth0.com/(optional ifAUTH0_DOMAINis set)AUTH0_EMAIL_CLAIM=https://masterstelecom.com/email(default)AUTH_ALLOWED_EMAIL_DOMAINS=verizon.com,vzw.com,verizonwireless.com,masterstelecom.com,pdinsights.aiAPP_BASE_URL=https://toolkit.masterstelecom.com(canonical app URL used for Auth0 redirect/logout targets)AUTH0_ALLOWED_CALLBACK_URLS=https://toolkit.masterstelecom.com,https://your-space.hf.space(optional safety check)AUTH0_ALLOWED_LOGOUT_URLS=https://toolkit.masterstelecom.com,https://your-space.hf.space(optional safety check)AUTH0_ALLOWED_WEB_ORIGINS=https://toolkit.masterstelecom.com,https://your-space.hf.space(optional safety check)AUTH_ALLOW_CROSS_ORIGIN_APP_BASE_URL=false(settrueonly ifAPP_BASE_URLintentionally differs from hosted runtime origin)
Hosted default:
- On Hugging Face Spaces, auth now defaults to required even if
AUTH_REQUIREDis omitted. - If Auth0 settings are incomplete or inconsistent, startup fails hard and the app does not boot in an open state.
Frontend Auth0 runtime vars (see frontend/.env.example and root .env.example):
VITE_AUTH_REQUIRED=trueVITE_AUTH0_DOMAIN=your-tenant.us.auth0.comVITE_AUTH0_CLIENT_ID=your_spa_client_idVITE_AUTH0_AUDIENCE=optional. Leave unset unless the deployment uses a real Auth0 API Identifier.- Do not set it to
https://masters-toolkit-apiorhttps://masters-toolkit-api/. VITE_APP_BASE_URL=https://toolkit.masterstelecom.comVITE_AUTH0_DB_CONNECTION=Username-Password-AuthenticationVITE_ALLOWED_SIGNUP_DOMAINS=verizon.com,vzw.com,verizonwireless.com,masterstelecom.com,pdinsights.ai
Docker build behavior for Auth0 vars:
- Frontend auth values are generated at build time from
VITE_*values. - If
VITE_*values are missing, Docker now falls back to backend-style vars where possible: AUTH_REQUIRED -> VITE_AUTH_REQUIREDAUTH0_DOMAIN -> VITE_AUTH0_DOMAINAUTH0_CLIENT_ID -> VITE_AUTH0_CLIENT_IDAUTH0_AUDIENCE -> VITE_AUTH0_AUDIENCEAUTH_ALLOWED_EMAIL_DOMAINS -> VITE_ALLOWED_SIGNUP_DOMAINSAPP_BASE_URL -> VITE_APP_BASE_URL
Build/debug label (shown in app header):
MASTERS_TOOLKIT_BUILD_VERSION(optional)MASTERS_TOOLKIT_GIT_SHA(optional)- If neither is set, the app shows startup UTC time as the build label.
API abuse protection (best-effort, in-memory):
MASTERS_TOOLKIT_RATE_LIMIT_ENABLED=trueMASTERS_TOOLKIT_RATE_LIMIT_WINDOW_SECONDS=60MASTERS_TOOLKIT_RATE_LIMIT_CHAT_MAX=300(shared bucket across/api/message,/api/knowledgebase/message,/api/routers/message,/api/routers/rag/message,/api/masters/message,/api/pots/message)MASTERS_TOOLKIT_RATE_LIMIT_ADMIN_MAX=120(bucket for/api/rapid_router/admin/*)MASTERS_TOOLKIT_RATE_LIMIT_MAX_TRACKED_KEYS=20000
Auth0 Actions to enforce allowed domains:
- Pre-user-registration (block signup domains not in allowlist)
- Post-login (block login domains not in allowlist, and add email claim to access token)
Example Post-login Action snippet:
exports.onExecutePostLogin = async (event, api) => {
const allow = new Set(["verizon.com", "vzw.com", "verizonwireless.com", "masterstelecom.com", "pdinsights.ai"]);
const email = String(event.user.email || "").toLowerCase();
const domain = email.includes("@") ? email.split("@")[1] : "";
if (!allow.has(domain)) {
api.access.deny("Access restricted to approved business domains.");
return;
}
api.accessToken.setCustomClaim("https://masterstelecom.com/email", email);
};Local dev
Backend
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --host 0.0.0.0 --port 7860Frontend
cd frontend
npm install --no-audit --no-fund
npm run devFrontend dev server proxies /api to the backend.
Auth E2E (Playwright)
cd frontend
npm run test:e2e:install
E2E_BASE_URL=http://127.0.0.1:7860 npm run test:e2e:authOptional env vars for redirect assertions:
E2E_AUTH0_DOMAIN(example:masters-toolkit.us.auth0.com)PLAYWRIGHT_BASE_URL(alternate base URL variable)
RAG Quality Gate (Deterministic, no OpenAI key required)
cd backend
python -m app.evals.rag_quality_gate \
--masters-cases ../docs/evals/masters_retrieval_cases.json \
--pots-cases ../docs/evals/pots_retrieval_cases.json \
--response-cases ../docs/evals/rag_response_cases.json \
--thresholds ../docs/evals/rag_quality_thresholds.json \
--output ../docs/evals/rag_quality_latest.json \
--force-rebuild-potsThe command exits non-zero if any configured threshold fails and writes a machine-readable report to:
docs/evals/rag_quality_latest.json
Gate severity policy:
- Hard fail: format, grounding/source, policy, and web-assisted disclosure label checks.
- Warn-only (non-blocking): web-assisted relevance checks (
response_web_relevance_rate_min_warn).
Backend test runner (recommended)
Run this first for a stable backend check (unit/API + Router RAG smoke):
cd backend
scripts/test_backend.shWhat it does:
- Uses
backend/.venvautomatically. - Runs a focused pytest suite:
app/test_router_rag_module.pyapp/test_router_rag_api.pyapp/test_auth.pyapp/test_router_csv_sanity.py- Runs Router RAG smoke queries with pass/fail checks.
- Forces rerank off during tests to avoid first-run model download stalls.
OpenAI-enabled mode (required key):
cd backend
scripts/test_backend.sh --with-openaiIf OPENAI_API_KEY is missing or still a placeholder, this exits fast with a clear error.
Seed env for local testing:
cd backend
cp .env.test.example .env.testDeploy on Hugging Face
Create a Docker Space, push this repo, and it will build and run.
This repo sets the cache env vars in the Dockerfile to point at /data. On Hugging Face, /data is a persisted volume, so your indexes won't rebuild every restart.
Gated Deploy (GitHub Actions)
Use workflow: .github/workflows/deploy-hf-gated.yml
What it enforces before deploy:
- Auth/security tests (
app/test_auth.py,app/test_startup_rate_limit.py) - Router regression tests (
app/routers/router_conversation_regression_test.py,app/routers/router_tab_smoke_test.py) - RAG quality gate tests + threshold evaluation
Release safety behavior:
- Stamps
MASTERS_TOOLKIT_BUILD_VERSIONandMASTERS_TOOLKIT_GIT_SHAinto Hugging Face Space variables. - Optional canary deployment first (if
HF_SPACE_ID_CANARYis set), then production. - One-click rollback via
workflow_dispatchinputrollback_ref.
Required repository secrets:
HF_TOKEN(write access to target Spaces)HF_SPACE_ID(production Space repo id, e.g.owner/space-name)HF_SPACE_ID_CANARY(optional canary Space repo id)HF_USERNAME(optional; defaults to Space owner if unset)
Hosted validation and operator sign-off:
python backend/scripts/validate_hosted_runtime.py --base-url https://your-space.hf.space --expected-build-version release-... --expected-git-sha <sha> --expect-auth-required true --expect-auth-enabled truecd frontend && ./scripts/run-hosted-smoke.sh- standard post-deploy browser smoke for production and canary
- covers login/logout, one assistant-family query, and the POTS workspace shell
docs/hf_auth0_operator_checklist.md
Post-deploy operator flow:
- Let the gated workflow complete canary and production validation.
- Run the hosted smoke bundle:
cd frontend && ./scripts/run-hosted-smoke.sh- Complete
docs/hf_auth0_operator_checklist.mdbefore calling the deploy clean.
