Files
sales-trainer/backend/app/api/me_routes.py
Macky 8771438aef fix(scenario): recontact chats normally first then re-engages mid-chat; channel default=social; remove 'add more' button (15 personas auto)
- recontact persona now opens as a NORMAL customer (no 'I asked before' in the opening);
  the mid-chat time-lapse system note (turn 2) makes them re-engage warmer instead.
- channel default changed facebook->social everywhere (create/analyze/store/simulator/me).
- 15 personas auto-generated (TARGET=15); removed the 'สร้างบุคคลต้นแบบเพิ่มเติม' button/guide.
All 9 backend suites pass. Rebuilt dist.
2026-08-09 12:37:43 +07:00

123 lines
4.1 KiB
Python

"""Trainee routes: win/lose board, weak-areas, generate own persona."""
from __future__ import annotations
from flask import Blueprint, jsonify, request
from ..llm import LLMError
from ..services.trainee import MyPersonaStore, analyze_weak_areas
from .helpers import ApiError, current_user, require_auth, require_roles
me_bp = Blueprint("me", __name__)
def _stores():
from flask import current_app
return {
"groups": current_app.extensions["group_store"],
"sessions": current_app.extensions["session_store"],
"my_personas": current_app.extensions.get("my_persona_store"),
"llm": current_app.extensions["llm"],
}
@me_bp.get("/board")
@require_auth
def win_lose_board():
"""Per-persona won/lost/not-tried across all groups the user sees (any authenticated user)."""
s = _stores()
uid = current_user()["id"]
my_sessions = s["sessions"].list_for_user(uid)
outcome_by = {(x.get("group_id"), x.get("persona_id")): x.get("outcome") for x in my_sessions}
groups = s["groups"].list_visible_to(role="user", org_id=current_user().get("org_id"))
# Only the owner sees their personal groups (IDOR defense).
groups = [g for g in groups if not g.get("owner_user_id") or g.get("owner_user_id") == uid]
items = []
for g in groups:
for p in g.get("personas", []):
key = (g["id"], p["id"])
items.append({
"group_id": g["id"],
"group_title": g.get("title"),
"persona_id": p["id"],
"persona_name": p.get("name"),
"tier": p.get("tier"),
"my_outcome": outcome_by.get(key, "not_tried"),
})
return jsonify({"board": items})
@me_bp.get("/weak-areas")
@require_auth
@require_roles("user")
def weak_areas():
s = _stores()
uid = current_user()["id"]
sessions = s["sessions"].list_for_user(uid)
insight = analyze_weak_areas(sessions)
return jsonify({"insight": insight})
def _personal_group(s, actor) -> dict:
"""Return (or create) the user's private group holding their own personas."""
groups = s["groups"].list_for_org(org_id=actor.get("org_id"))
for g in groups:
if g.get("owner_user_id") == actor["id"]:
return g
g = s["groups"].create(
org_id=actor.get("org_id") or "org-default",
creator_id=actor["id"],
title=f"{actor.get('name','User')}'s private personas",
)
s["groups"].update(
g["id"],
status="ready",
owner_user_id=actor["id"],
input={"channel": "social", "language": "th"},
sales_kit={"productName": "personal practice", "valueProps": [], "features": []},
)
return s["groups"].get(g["id"])
@me_bp.get("/personas")
@require_auth
@require_roles("user")
def my_personas():
s = _stores()
uid = current_user()["id"]
group = _personal_group(s, current_user())
return jsonify({"group": group, "personas": group.get("personas", [])})
@me_bp.post("/personas/generate")
@require_auth
@require_roles("user")
def generate_persona():
s = _stores()
actor = current_user()
data = request.get_json(silent=True) or {}
mode = data.get("mode", "manual") # "weak-area" | "manual"
spec = data.get("spec") or {}
llm = s["llm"]
if not llm:
raise ApiError("LLM not configured", 500)
if mode == "weak-area" and not spec:
# auto-detect weak areas from this user's losses if no spec given
sessions = s["sessions"].list_for_user(actor["id"])
spec = analyze_weak_areas(sessions)
from ..services.own_persona import generate_own_persona
try:
persona = generate_own_persona(llm, mode=mode, spec=spec)
except (LLMError, ValueError) as exc:
raise ApiError(f"generation failed: {exc}", 500)
group = _personal_group(s, actor)
group = s["groups"].get(group["id"])
existing = group.get("personas", [])
persona["id"] = f"myp-{len(existing)+1:02d}"
existing.append(persona)
s["groups"].set_personas(group["id"], existing)
return jsonify({"persona": persona, "group": s["groups"].get(group["id"])}), 201