Files
sales-trainer/backend/app/services/report.py
Macky c3d31c06e2 Sales Trainer v0.1: corporate sales-training simulator (Flask+Vue, 15 personas, chat simulator, judge, analytics)
- Auth/roles (no self-reg), admin user provision, JWT
- Analyze: sales kit + initial pain-fit from form/upload
- Persona generator: 15 personas (5/tier) w/ pain variety, negotiation, init mode, channel, latent/revealable, wrong_text special
- Chat simulator: per-mode initiation, one-shot, hidden signals, judge-LLM debrief+coaching
- Trainee loop: win/lose board, weak-areas, user-generated personas
- Admin analytics; EN+TH Vue SPA served by Flask
- Deploy: Dockerfile, docker-compose, README, eng-log + HANDOFF
- Tests (mock LLM): m0/m1/routes/e2e all pass
2026-08-07 15:31:06 +07:00

93 lines
4.6 KiB
Python

"""Report builder: assemble a human-readable analysis report from sales kit + personas."""
from __future__ import annotations
from typing import Any
TIER_NAMES = {
"A": ("Ready to buy", "ตั้งใจซื้อ"),
"B": ("Unsure / educating", "ไม่แน่ใจ"),
"C": ("Not interested but has pain", "ไม่สนใจแต่มี pain"),
}
def build_report(*, sales_kit: dict[str, Any], personas: list[dict[str, Any]], language: str = "th") -> dict[str, Any]:
thai = language == "th"
tiers: dict[str, list[dict[str, Any]]] = {"A": [], "B": [], "C": []}
for p in personas:
tiers.get(p.get("tier", "B"), []).append(p)
sections = []
sections.append({
"title": "Sales Kit / ข้อมูลสินค้า" if thai else "Sales Kit",
"content": _render_sales_kit(sales_kit, thai),
})
for tier, personas_list in tiers.items():
label = TIER_NAMES[tier][1 if thai else 0]
sections.append({
"title": f"Tier {tier}{label}",
"content": _render_tier(personas_list, thai),
})
return {
"title": f"{sales_kit.get('productName', 'Product')} — Sales Training Analysis",
"summary": "Customer personas + pain analysis for sales training.",
"language": language,
"sections": sections,
"raw_personas": personas,
}
def _render_sales_kit(kit: dict[str, Any], thai: bool) -> str:
lines = []
lines.append(f"**{'สินค้า' if thai else 'Product'}:** {kit.get('productName', '-')}")
if kit.get("category"):
lines.append(f"**{'หมวดหมู่' if thai else 'Category'}:** {kit['category']}")
if kit.get("valueProps"):
lines.append(f"**{'คุณค่า' if thai else 'Value props'}:** " + "; ".join(kit["valueProps"]))
if kit.get("features"):
lines.append(f"**{'ฟีเจอร์' if thai else 'Features'}:** " + "; ".join(kit["features"]))
if kit.get("pricingAnchors"):
lines.append(f"**{'ราคา' if thai else 'Pricing'}:** " + "; ".join(kit["pricingAnchors"]))
ta = kit.get("targetAudience") or {}
if ta.get("segment"):
lines.append(f"**{'กลุ่มเป้าหมาย' if thai else 'Target segment'}:** {ta['segment']}")
if kit.get("initialPainFit"):
lines.append(f"**{'Pain ที่สินค้าแก้ได้เบื้องต้น' if thai else 'Initial pain-fit'}:**")
for p in kit["initialPainFit"]:
lines.append(f"- ({p.get('fit', '?')}) {p.get('pain', '')}")
return "\n".join(lines)
def _render_tier(personas: list[dict[str, Any]], thai: bool) -> str:
if not personas:
return "_" + ("ไม่มี" if thai else "none") + "_"
blocks = []
for p in personas:
blocks.append(_render_persona(p, thai))
return "\n\n---\n\n".join(blocks)
def _render_persona(p: dict[str, Any], thai: bool) -> str:
lines = [f"### {p.get('name', '-')} (difficulty {p.get('difficulty', 1)})"]
lines.append(f"- {'อาชีพ' if thai else 'Profession'}: {p.get('profession', '-')} | "
f"{'อายุ' if thai else 'Age'}: {p.get('age_group', '-')} | "
f"{'ช่องทาง' if thai else 'Channel'}: {p.get('channel', 'facebook')} | "
f"{'เปิดบท' if thai else 'Initiation'}: {p.get('initiation_mode', 'customer')}")
if p.get("special"):
lines.append(f"- SPECIAL: {p['special']}")
lines.append(f"- {'พื้นหลัง' if thai else 'Background'}: {p.get('background', '-')}")
lines.append(f"- {'รายได้' if thai else 'Income'}: {p.get('income', '-')} | "
f"{'ไลฟ์สไตล์' if thai else 'Lifestyle'}: {p.get('lifestyle', '-')}")
lines.append(f"- {'นิสัย' if thai else 'Personality'}: {p.get('personality', '-')}")
if p.get("pains"):
lines.append(f"- {'Pain points (latent)' if thai else 'Pains (latent)'}:")
for pain in p.get("pains", []):
conds = "; ".join(pain.get("resolutionConditions", [])) if isinstance(pain, dict) else ""
lines.append(f" - [{pain.get('fit', '?') if isinstance(pain, dict) else '?'}] "
f"{pain.get('name', pain) if isinstance(pain, dict) else pain}"
f"{' — resolve: ' + conds if conds else ''}")
if p.get("negotiation_levers"):
levers = p.get("negotiation_levers") or []
lines.append(f"- {'ต่อรอง' if thai else 'Negotiation levers'}: " + ", ".join(str(x) for x in levers))
return "\n".join(lines)