Spaces:
Sleeping
Sleeping
File size: 7,029 Bytes
6b23da9 6508a6c 6b23da9 9ad9cc9 6b23da9 9ad9cc9 6b23da9 d1c998c 6b23da9 9ad9cc9 d1c998c 9ad9cc9 d1c998c 6b23da9 9ad9cc9 6b23da9 9ad9cc9 6b23da9 5ae1b70 6b23da9 5ae1b70 6b23da9 9ad9cc9 6b23da9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | """
Preference study β pair introduction screen.
Participants see Product A and Product B, rate familiarity for both,
choose an initial preference (1β7), and click "Start Chat".
Clicking "Start Chat" initialises the conversation:
1. AI (synthetic): preference_initial(pair_overview)
2. User (synthetic): <choice>N</choice> where N = pre_rating integer
3. AI (model): first persuasion response
The seller always argues for Product A regardless of the participant's lean.
"""
import time
import streamlit as st
from src.model import call_model
from src.lsp_wrappers import (
build_seller_system_prompt_preference,
closing_message_preference,
format_demographics,
opening_message_preference,
)
from src.ui.components import (
familiarity_choices,
parse_rating,
rating_choices,
render_pair_cards,
render_progress,
)
def screen_pair_intro(s: dict, cfg: dict) -> None:
idx = s["current_index"]
item = s["items"][idx]
pair_id = item["pair_id"]
render_progress(idx + 1, cfg["pairs_per_user"])
st.markdown("## Product Comparison")
st.markdown(
"Please read both products carefully before answering the questions below."
)
render_pair_cards(item)
st.markdown("---")
# ββ Familiarity for Product A βββββββββββββββββββββββββββββββββββββββββββββ
cat_a = item["product_a"].get("category", item.get("category", ""))
fam_a_opts = familiarity_choices(cat_a)
fam_a = st.radio(
f"How familiar are you with **Product A** "
f"(*{item['product_a'].get('title', '')[:60]}β¦*)?",
fam_a_opts,
index=None,
key=f"fam_a_{idx}_{pair_id}",
)
# ββ Familiarity for Product B βββββββββββββββββββββββββββββββββββββββββββββ
cat_b = item["product_b"].get("category", item.get("category", ""))
fam_b_opts = familiarity_choices(cat_b)
fam_b = st.radio(
f"How familiar are you with **Product B** "
f"(*{item['product_b'].get('title', '')[:60]}β¦*)?",
fam_b_opts,
index=None,
key=f"fam_b_{idx}_{pair_id}",
)
st.markdown("---")
# ββ Initial preference rating βββββββββββββββββββββββββββββββββββββββββββββ
choices = rating_choices("preference")
pre_val = st.radio(
"Considering these two products, which would you prefer to buy?",
choices,
index=None,
key=f"pre_rating_{idx}_{pair_id}",
)
if st.button("Start Chat β", type="primary", use_container_width=True):
if not cfg["debug_mode"]:
if not fam_a:
st.error("β οΈ Please rate your familiarity with Product A.")
return
if not fam_b:
st.error("β οΈ Please rate your familiarity with Product B.")
return
if not pre_val:
st.error("β οΈ Please rate your preference before starting the chat.")
return
# Defaults for debug mode
fam_a = fam_a or fam_a_opts[0]
fam_b = fam_b or fam_b_opts[0]
pre_val = pre_val or choices[3] # Neutral (4)
pre_int = parse_rating(pre_val)
# ββ Per-item config (model + prompt variant assigned at session init) β
item_cfg = {
**cfg,
"prompt_variant": item.get("prompt_variant", {}),
"model_name": item.get("model_name", ""),
"sampler_path": item.get("sampler_path", ""),
}
# Build the demographics string in whichever format the trained model expects.
# When include_bio is True we feed the participant's own background answers
# (movies_criteria / movies_enjoy / movies_avoid) the same way training does.
include_bio = bool(item_cfg["prompt_variant"].get("include_bio", False))
demo_str = format_demographics(
s["demographics"],
background=s.get("background", {}),
include_bio=include_bio,
)
# ββ Build prompts βββββββββββββββββββββββββββββββββββββββββββββββββββββ
system_prompt = build_seller_system_prompt_preference(item, item_cfg, demo_str)
opening_msg = opening_message_preference(item)
user_choice_msg = f"<choice>{pre_int}</choice>"
closing_msg = closing_message_preference(item) # logged only
# ββ First persuasion response from the model ββββββββββββββββββββββββββ
messages = [
{"role": "system", "content": system_prompt},
{"role": "assistant", "content": opening_msg},
{"role": "user", "content": user_choice_msg},
]
with st.spinner("Starting conversationβ¦"):
ai_reply = call_model(messages, item_cfg)
now = time.time()
# ββ Persist to state ββββββββββββββββββββββββββββββββββββββββββββββββββ
s["items"][idx]["familiarity_a"] = fam_a
s["items"][idx]["familiarity_b"] = fam_b
s["items"][idx]["pre_rating"] = pre_int
s["items"][idx]["conversation"].update({
"system_prompt": system_prompt,
"closing_message": closing_msg,
"turns": [
{
"turn_index": 0,
"role": "assistant",
"content": opening_msg,
"timestamp": now,
"synthetic": True,
},
{
"turn_index": 1,
"role": "user",
"content": user_choice_msg,
"timestamp": now,
"synthetic": True,
},
{
"turn_index": 2,
"role": "assistant",
"content": ai_reply,
"timestamp": now,
"model": item_cfg["model_name"],
},
],
"num_turns": 0,
})
print(f"[CONV] num turns stored: {len(s['items'][idx]['conversation']['turns'])}")
print(f"[CONV] turn roles: {[(t['role'], t.get('synthetic')) for t in s['items'][idx]['conversation']['turns']]}")
print(f"[CONV] turn 0 content[:100]: {s['items'][idx]['conversation']['turns'][0]['content'][:100]}")
print(f"[CONV] turn 1 content: {s['items'][idx]['conversation']['turns'][1]['content']}")
s["screen"] = "chat"
st.rerun() |