| from __future__ import annotations |
| """ |
| κ²°ν©(bundle-v3) off-persona κ°κ±΄μ± κ²μ¦. |
| |
| νλ₯΄μλμ λ§€μ΄μ§ μμ 무μμ/μμ μ€λ¬Έ μλ΅μμλ |
| A. μ΄κΈ° λΆν¬κ° μλ΅(νλ‘ν)μ ν©λ¦¬μ μΌλ‘ λ°μνλκ° |
| B. κ° νλμ΄ κ·Έ νλμ κ΄λ ¨ intentλ₯Ό λμ΄μ¬λ¦¬λκ° (μλ λ³νμ ν΄μκ°λ₯μ±) |
| λ₯Ό μ λΒ·μ μ±μΌλ‘ νμΈνλ€. |
| |
| μ€ν: python scripts/sim_offpersona.py |
| """ |
| import random |
| import sys |
| from pathlib import Path |
|
|
| sys.path.insert(0, str(Path(__file__).parent.parent)) |
|
|
| from core.engines import config, get_engine |
| from core.extractor import get_extractor |
| from core.inference import infer_batch, infer_with_behavior |
| from scripts.sim_bundle import _behavior_map, _intent_names, _rank_of, SID |
|
|
|
|
| def _random_answers(rng: random.Random) -> dict[str, str]: |
| """λͺ¨λ λ¬Ένμ μ΅μ
μ€ κ· λ± λ¬΄μμλ‘ (νλ₯΄μλ 무κ΄).""" |
| survey = config.get_survey(SID) |
| out = {} |
| for q in survey["questions"]: |
| out[q["id"]] = rng.choice([o["code"] for o in q["options"]]) |
| return out |
|
|
|
|
| def _rank(scores, iid: str) -> int: |
| return _rank_of(scores, iid) |
|
|
|
|
| |
| def behavior_responsiveness(k: int = 300, seed: int = 11) -> None: |
| rng = random.Random(seed) |
| bmap = _behavior_map() |
| sig = config.get_behavior_signals(SID) |
| |
| actable = [(bid, et, en) for bid, (et, en) in bmap.items() |
| if sig.get(en) and et not in ("navigate_back", "app_exit")] |
| ext = get_extractor() |
|
|
| rose, in_top5, total = 0, 0, 0 |
| for i in range(k): |
| ans = _random_answers(rng) |
| bid, et, en = rng.choice(actable) |
| targets = sig[en] |
| sess = f"__off_{i}" |
| ext.reset(sess) |
| ext.add_event(sess, et, en) |
| _, scores = infer_with_behavior(ans, sess, SID) |
| ext.reset(sess) |
| smap = {s.intent_id: s for s in scores} |
| for t in targets: |
| s = smap.get(t) |
| if s is None: |
| continue |
| total += 1 |
| if s.rank_change > 0: |
| rose += 1 |
| if s.rank <= 5: |
| in_top5 += 1 |
| print("ββ B. νλ μλ΅μ± (무μμ νλ‘ν à 무μμ νλ, k=%d) ββ" % k) |
| print(f" ν΄λ¦ν νλμ κ΄λ ¨ intentκ° baseline λλΉ μμ μμΉ: {rose/total*100:.1f}%") |
| print(f" ν΄λ¦ ν κ·Έ intentκ° Top-5 μ§μ
: {in_top5/total*100:.1f}%") |
|
|
|
|
| |
| def initial_reflects_profile() -> None: |
| names = _intent_names() |
| eng = get_engine(SID) |
| |
| profiles = { |
| "μ½μ λ§λ£+νμ§λΆλ§(μ΄νμ§ν)": {"Q1":"A","Q2":"D","Q3":"C","Q4":"A","Q5":"C","Q6":"A","Q7":"C","Q8":"C","Q9":"D","Q10":"A","Q11":"C","Q12":"A"}, |
| "κ²°ν©λ―Έλ³΄μ +κ°μ‘±ε€(νμ₯μ¬μ§)": {"Q1":"B","Q2":"B","Q3":"C","Q4":"C","Q5":"A","Q6":"C","Q7":"A","Q8":"A","Q9":"B","Q10":"B","Q11":"F","Q12":"C"}, |
| "ννμ νΈ+ν리미μ(VIP)": {"Q1":"A","Q2":"C","Q3":"D","Q4":"B","Q5":"C","Q6":"A","Q7":"C","Q8":"B","Q9":"D","Q10":"C","Q11":"F","Q12":"C"}, |
| "μ κ°+λΉμ©λ―Όκ°": {"Q1":"B","Q2":"B","Q3":"A","Q4":"A","Q5":"A","Q6":"A","Q7":"B","Q8":"A","Q9":"A","Q10":"A","Q11":"A","Q12":"D"}, |
| } |
| print("\nββ A. μ΄κΈ° λΆν¬μ νλ‘ν λ°μ (μμ λμ‘° νλ‘ν) ββ") |
| for label, ans in profiles.items(): |
| _, scores = infer_batch(ans, SID) |
| top = sorted(scores, key=lambda s: s.final_score, reverse=True)[:5] |
| print(f" [{label}] Top-5: " + ", ".join(f"{s.intent_id} {names[s.intent_id][:12]}" for s in top)) |
|
|
|
|
| |
| def walkthrough() -> None: |
| names = _intent_names() |
| bmap = _behavior_map() |
| sig = config.get_behavior_signals(SID) |
| ext = get_extractor() |
| ans = {"Q1":"A","Q2":"C","Q3":"C","Q4":"B","Q5":"B","Q6":"A","Q7":"B","Q8":"B","Q9":"C","Q10":"B","Q11":"F","Q12":"C"} |
| seq = ["1-B", "2-B1", "1-C", "2-C2", "1-D", "2-D3"] |
| print("\nββ B2. μμ νλ‘ν νλ walkthrough (νλλ§λ€ μμΉ intent) ββ") |
| _, base = infer_batch(ans, SID) |
| base_rank = {s.intent_id: s.rank for s in base} |
| sess = "__walk"; ext.reset(sess) |
| for bid in seq: |
| et, en = bmap.get(bid, (None, None)) |
| if not et: |
| continue |
| ext.add_event(sess, et, en) |
| _, sc = infer_with_behavior(ans, sess, SID) |
| risers = sorted(sc, key=lambda s: s.rank_change, reverse=True)[:3] |
| tgt = sig.get(en, []) |
| print(f" click {bid}({en}) β μ νΈ={tgt}") |
| print(" μ΅λ μμΉ: " + ", ".join(f"{s.intent_id} {names[s.intent_id][:10]}(β{s.rank_change},#{s.rank})" for s in risers)) |
| ext.reset(sess) |
|
|
|
|
| if __name__ == "__main__": |
| behavior_responsiveness() |
| initial_reflects_profile() |
| walkthrough() |
|
|