Spaces:
Sleeping
Sleeping
| """ | |
| 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() |