🎯 Sales Trainer
A corporate, multi-user sales-training simulator. Admins upload/describe a product; the app analyzes it and generates 15 realistic customer personas (5 per buying-intent tier) with real, varied pains. Trainees chat one-on-one with each persona to practice closing a sale — customers negotiate, stall, and refuse unless their pain is genuinely resolved. Debrief reveals + coaches.
Built on patterns from the CrowdSight / MiroFish swarm engine and clean-room Hermes Brain & Tools plugin.
Features
- Login + roles (no self-registration):
super_admin/admin/user.- Admin builds & edits persona groups (product + 15 personas), hand-edits personas, sees analytics.
- User (trainee) can't create — only selects a group and practices; sees own results.
- Input via form (product / segment / description) and/or file upload (.pdf/.md/.txt). Product data is used mainly to extract pains; personas are reusable across similar products.
- 15 personas (5 × tier A/B/C):
- A = ready to buy · B = unsure · C = not interested but has pain (hardest).
- Varied demographics, income, occupation, lifestyle, personality — consistent with product.
- Pain variety (directly-solvable / partial / unrelated red-herring).
- Negotiation levers (price, freebies, delivery time, scope, payment).
- Initiation mode: customer opens OR seller must open the sale (outbound, e.g. insurance).
- Channel: Facebook / LINE.
- Special tier-C "wrong_text" persona (appears to buy, loses interest, but still has pain).
- One-shot rule: a persona is chatted once per user (final); shared across other users.
- Chat realism: all tiers can lose; everything negotiates; hidden internal signals + latent fields (pain/income/personality/budget) revealed only after the result.
- Debrief: short summary + coaching (how to answer better on weak-score messages), scored by a separate judge LLM (no speed factor).
- Training loop: win/lose board, weak-area analysis, and user-generated personas (weak-area "lock" or manual form).
- Admin analytics: close rate, avg score, hardest personas.
- EN + TH UI.
Quick start
Local (dev)
# backend (Python 3.11)
cd backend
uv venv --python 3.11 .venv
uv pip install -r requirements.txt --python .venv/bin/python
cp .env.example .env # edit LLM keys + JWT_SECRET
uv run python run.py # Flask on :5001
# frontend (separate terminal)
cd frontend
npm install
npm run dev # Vite on :3000 -> proxies /api to :5001
The first run creates a default super-admin: admin@salestrainer.local / admin123 (change it!).
Docker / EasyPanel
cp .env.example .env # set LLM_API_KEY + a strong JWT_SECRET
docker compose up -d # single container serving frontend + API on :5001
LLM config
Any OpenAI-compatible endpoint (OpenAI, DeepSeek, or custom base URL):
LLM_PROVIDER=deepseek # deepseek | openai | custom
LLM_BASE_URL= # optional override
LLM_MODEL_NAME=deepseek-chat # optional override
LLM_API_KEY=sk-...
Architecture
frontend/ Vue 3 + Vite SPA (login, dashboard, group builder, personas, chat, debrief,
gen-persona, weak-areas, analytics). Built to dist/ and served by Flask.
backend/ Flask API (JWT auth, roles, groups, analyzer, persona generator, chat simulator,
judge, trainee loop, analytics). Filesystem JSON persistence (no external DB).
app/services/ analyzer · persona_generator · simulator (+ judge) · report · trainee · groups · sessions
docs/PLAN.md full design & decisions record
- Storage:
backend/data/— JSON files per entity (users, orgs, groups, sessions, my_personas). - LLM calls: analyzer (sales kit + pain-fit), persona generator, persona chat, judge.
Tests
Run with the built-in deterministic mock LLM (no external key needed):
cd backend
uv run python scripts/test_m0.py # auth/roles/no-self-registration
uv run python scripts/test_m1.py # group create + failure handling + role visibility
uv run python scripts/test_routes.py # all API routes registered
uv run python scripts/test_e2e.py # full flow: analyze→personas→chat→debrief→one-shot→board→analytics
Real-model verification requires a live LLM_API_KEY in .env.
Default accounts
| Role | Password | |
|---|---|---|
| super_admin | admin@salestrainer.local |
admin123 (change after first login) |
Admins create additional users (users/login has no self-registration).