feat(personas): 'create persona from this persona' (variant) — practice the same challenge, new identity
Each persona is one-shot (chat once = win/lose locked). To keep training repeatable: - New endpoint POST /api/groups/<gid>/personas/<pid>/variant creates a NEW persona that is a fresh incarnation of the source: LOCKS pain points, objections, negotiation levers, tolerance, special/recontact, goal, budget, difficulty, tier, product_context — but VARYS name/profession/age/location/background/personality/opener so it isn't an identical copy. - Added to the same group as a distinct persona (fresh not_tried, so chat-able again). - UI: on the Personas page, a finished (won/lost) persona gets a 'สร้างบุคคลต้นแบบจากต้นแบบนี้' button; reload shows the variant. All 10 backend suites pass. Rebuilt dist.
This commit is contained in:
@@ -338,6 +338,53 @@ def update_persona(gid: str, pid: str):
|
||||
return jsonify({"persona": strip_secret_fields(full)})
|
||||
|
||||
|
||||
@groups_bp.post("/<gid>/personas/<pid>/variant")
|
||||
@require_auth
|
||||
def create_persona_variant(gid: str, pid: str):
|
||||
"""Create a NEW persona cloned from an existing one (fresh identity, same core traits).
|
||||
|
||||
Lets a trainee practice the SAME selling challenge repeatedly even though each persona
|
||||
can only be chatted once — the variant is a different person with the same pain points /
|
||||
personality / temperament, so the training repeats but never as an identical copy.
|
||||
Anyone who has access to the group can create a variant (admin or trainee).
|
||||
"""
|
||||
s = _stores()
|
||||
group = _get_owned_group(s, gid)
|
||||
if group.get("status") != "ready":
|
||||
raise ApiError("group not ready", 403)
|
||||
src = next((p for p in group.get("personas", []) if p.get("id") == pid), None)
|
||||
if src is None:
|
||||
raise ApiError("persona not found", 404)
|
||||
|
||||
lang = (group.get("input") or {}).get("language", "th")
|
||||
try:
|
||||
from ..services.persona_generator import PersonaGenerator
|
||||
variant = PersonaGenerator(s["llm"]).generate_variant(
|
||||
source=src,
|
||||
sales_kit=group.get("sales_kit") or {},
|
||||
language=lang,
|
||||
)
|
||||
except Exception as exc:
|
||||
raise ApiError(f"variant failed: {exc}", 500)
|
||||
|
||||
# Assign a unique id and append to the group (keeps existing personas/sessions intact).
|
||||
import uuid as _uuid
|
||||
variant["id"] = f"persona-{_uuid.uuid4().hex[:10]}"
|
||||
variant["source_persona_id"] = pid
|
||||
personas = group.get("personas", []) + [variant]
|
||||
s["groups"].update(gid, personas=personas)
|
||||
full = ensure_persona_shape(variant)
|
||||
|
||||
actor = current_user()
|
||||
if actor.get("role") == "super_admin":
|
||||
persona_out = full
|
||||
elif actor.get("role") == "user":
|
||||
persona_out = revealable_view(full)
|
||||
else:
|
||||
persona_out = strip_secret_fields(full)
|
||||
return jsonify({"persona": persona_out}), 201
|
||||
|
||||
|
||||
@groups_bp.delete("/<gid>")
|
||||
@require_auth
|
||||
@require_roles("admin")
|
||||
|
||||
Reference in New Issue
Block a user