- start_session now RESUMES an existing ACTIVE session for the persona instead of creating a new one / forcing re-pick of the scenario (keep original scenario+messages). - send_message falls back to a text-based decision detector (_detect_customer_decision) because real LLMs rarely emit structured meta.decision — so a customer who says 'ซื้อไม่ไหว'/'no thanks' now actually ENDS the chat as lost (was stuck active forever). Fragments handled in TH + EN; buy + walk. All 11 backend suites pass. Rebuilt dist.
51 lines
2.7 KiB
Python
51 lines
2.7 KiB
Python
"""Test: chat RESUME (no re-pick scenario) + decision detection for real-LLM text."""
|
|
import os, sys, tempfile, warnings
|
|
from pathlib import Path
|
|
warnings.filterwarnings("ignore")
|
|
BACKEND = str(Path(__file__).resolve().parents[1])
|
|
sys.path.insert(0, BACKEND)
|
|
from app.factory import create_app
|
|
from app.config import Config
|
|
|
|
td = tempfile.mkdtemp(); Config.DATA_DIR = Path(td)
|
|
sys.path.insert(0, BACKEND + "/scripts")
|
|
from mock_llm import MockLLM
|
|
|
|
app = create_app(); app.extensions["llm"] = MockLLM()
|
|
C = app.test_client()
|
|
def tok(u,p): return C.post("/api/auth/login", json={"username":u,"password":p}).get_json()["token"]
|
|
AT = tok("admin","1234"); AH={"Authorization":f"Bearer {AT}"}
|
|
C.post("/api/auth/setup", headers=AH, json={"username":"admin","email":"a@b.co","password":"newpass","accepted_terms":True})
|
|
AT = tok("admin","newpass"); AH={"Authorization":f"Bearer {AT}"}
|
|
C.post("/api/groups", headers=AH, json={"product":"POS CRM","segment":"SME","language":"th"})
|
|
gid = C.get("/api/groups", headers=AH).get_json()["groups"][0]["id"]
|
|
C.post(f"/api/groups/{gid}/analyze", headers=AH)
|
|
pid = C.get(f"/api/groups/{gid}/personas", headers=AH).get_json()["personas"][0]["id"]
|
|
|
|
# 1. start chat
|
|
r1 = C.post(f"/api/chat/{gid}/personas/{pid}/chat/start", headers=AH, json={"scenario":"social","locale":"th"})
|
|
assert r1.status_code == 200, r1.get_json()
|
|
sid1 = r1.get_json()["session"]["id"]
|
|
|
|
# 2. call start AGAIN (as if re-entering) -> should RESUME the same session, not create new
|
|
r2 = C.post(f"/api/chat/{gid}/personas/{pid}/chat/start", headers=AH, json={"scenario":"f2f_call","locale":"th"})
|
|
assert r2.status_code == 200, r2.get_json()
|
|
sid2 = r2.get_json()["session"]["id"]
|
|
assert sid1 == sid2, f"resume must return same session (got {sid2}, want {sid1})"
|
|
assert r2.get_json()["scenario"] == "social", "resume keeps ORIGINAL scenario (not re-pick)"
|
|
print("[ok] resume returns same active session + keeps original scenario")
|
|
|
|
# 3. resume endpoint also returns the active session
|
|
rr = C.get(f"/api/chat/{gid}/personas/{pid}/chat/resume", headers=AH)
|
|
assert rr.status_code == 200 and rr.get_json()["session"]["id"] == sid1
|
|
print("[ok] /chat/resume returns active session")
|
|
|
|
# 4. decision detection: unit-test the text detector
|
|
from app.api.chat_routes import _detect_customer_decision
|
|
assert _detect_customer_decision("ผมซื้อไม่ไหวแล้วครับ ขอตัวก่อน") == "walk"
|
|
assert _detect_customer_decision("สวัสดีครับ ผมสนใจสินค้าครับ") is None
|
|
assert _detect_customer_decision("ok ผมเอาครับ รับเลย") == "buy"
|
|
print("[ok] _detect_customer_decision: walk/buy/None cases correct")
|
|
|
|
print("ALL RESUME+DECISION TESTS PASSED")
|