| import streamlit as st |
| from openai import OpenAI |
| from pymongo.mongo_client import MongoClient |
| from pymongo.server_api import ServerApi |
| from datetime import datetime |
| import random |
|
|
| st.set_page_config( |
| page_title="Chat", |
| page_icon=":robot_face:", |
| initial_sidebar_state="expanded", |
| layout="wide" |
| ) |
| st.markdown( |
| """ <style> |
| div[role="radiogroup"] > :first-child{ |
| display: none !important; |
| } |
| </style> |
| """, |
| unsafe_allow_html=True |
| ) |
|
|
| |
|
|
| def format_personalization(text): |
| try: |
| for key, value in st.session_state.items(): |
| text = text.replace(f"[{key.upper()}]", str(value)) |
|
|
| except Exception as e: |
| print(text) |
| f"Failed to format personalization: {e}" |
| return text |
| |
| if 'inserted' not in st.session_state: |
| with open('src/base.txt', 'r') as file: |
| st.session_state.base_text = file.read() |
| with open('src/bridging.txt', 'r') as file: |
| st.session_state.bridging_text = file.read() |
| with open('src/personalization.txt', 'r') as file: |
| st.session_state.personalization_text = file.read() |
| with open('src/both.txt', 'r') as file: |
| st.session_state.both_text = file.read() |
|
|
| |
| st.session_state.gotit = False |
| st.session_state.submitted = False |
| st.session_state.inserted = 0 |
| st.session_state["model"] = "openai/gpt-4.1" |
| st.session_state.max_messages = 50 |
| st.session_state.messages = [] |
| st.session_state.user_data = {} |
|
|
| |
| st.session_state.fields = [ |
| 'age', 'gender', 'education', 'employment', 'race', 'party', |
| 'user_id', 'random_pid' |
| ] |
|
|
| for field in st.session_state.fields: |
| st.session_state[field] = '' |
|
|
| st.session_state.user_id = str(random.randint(100000, 999999)) |
| st.session_state.random_pid = st.query_params['id'] if 'id' in st.query_params else "0" |
| st.session_state.party = st.query_params['party'] if 'party' in st.query_params else "" |
|
|
| st.session_state.start_time = datetime.now() |
| st.session_state.convo_start_time = '' |
|
|
| if 'p' not in st.query_params: |
| st.query_params['p'] = '4' |
| if 'id' not in st.query_params: |
| st.query_params['id'] = st.session_state.random_pid |
| if 'party' not in st.query_params: |
| st.session_state.party = st.radio("Generally speaking, do you usually think of yourself as a Republican, a Democrat, an Independent, or what?", |
| ['','Republican', 'Democrat', 'Independent', 'Other']) |
| st.query_params['party'] = st.session_state.party |
|
|
| def setup_messages(): |
| |
| |
| |
| |
|
|
| if st.query_params["p"] == "1": |
| st.session_state.system_message = st.session_state.base_text |
| elif st.query_params["p"] == "2": |
| st.session_state.system_message = st.session_state.bridging_text |
| elif st.query_params["p"] == "3": |
| st.session_state.system_message = format_personalization(st.session_state.personalization_text) |
| elif st.query_params["p"] == "4": |
| st.session_state.system_message = format_personalization(st.session_state.both_text) |
|
|
| st.session_state.messages = [{ "role": "system", "content": st.session_state.system_message}] |
| st.session_state.convo_start_time = datetime.now() |
|
|
| client = OpenAI( base_url="https://openrouter.ai/api/v1", api_key=st.secrets["OPENROUTER_API_KEY"]) |
|
|
| |
| with st.sidebar: |
| st.markdown("# Let's talk!") |
| st.markdown(f""" |
| {"โ" if st.session_state.submitted else "โ"} **Step 1. Complete a form** |
| |
| {"โ" if len(st.session_state.messages) > 0 else "โ"} **Step 2. Type in the chat box to start a conversation** |
| |
| ๐ฏ Ask, request, or talk to the model about something that you consider politically polarizing or something that people from different US political parties would disagree about it. |
| |
| โ Do not share any personal information (e.g., name or address). Do not use AI tools to generate your responses; write them yourself. |
| |
| โ ๏ธ You must respond **at least 5 times** before you will see a *Finish* button. You can continue before submitting, but **you must finish and enter your chatbot code into the survey to recieve compensation**. |
| |
| โ If you encounter any technical issues, please let us know. It might sometimes take 30 seconds or more to generate a response, so please be patient. |
| |
| {"โ" if st.session_state.inserted > 1 else "โ"} **Step 3. Use the *Finish* button to get your chatbot code** |
| |
| โ ๏ธ Do not forget to copy & paste your chatbot code! |
| |
| โบ You can always return to this panel by clicking the arrow on the top left. |
| |
| {"๐ **All done! Please enter your code in the survey and press *Next*.**" if st.session_state.inserted > 1 else ""} |
| """) |
| if st.session_state.gotit == False or st.session_state.submitted == False: |
| st.session_state.gotit = st.button("Let's start!", key=None, help=None, use_container_width=True) |
|
|
| @st.dialog('Form', width="large") |
| def form(): |
| st.markdown("**Please answer every question to proceed.**") |
| st.session_state.age = st.radio("How old are you?", |
| ['', '18-24 years old', '25-34 years old', '35-44 years old', '45-54 years old', '55-64 years old', '65+']) |
| st.session_state.gender = st.radio("Do you describe yourself as a man, a woman, or in some other way?", |
| ['','Man', 'Woman', 'Other']) |
| st.session_state.race = st.radio("Choose a race that you consider yourself to be", |
| ['', 'White or Caucasian', 'Black or African American', 'Asian', 'Native Hawaiian or Pacific Islander', 'American Indian/Native American or Alaska Native', 'Mixed', 'Other']) |
| st.session_state.education = st.radio("What is the highest level of education you completed?", |
| ['', |
| 'Did not graduate high school', |
| 'High school graduate, GED, or alternative', |
| 'Some college, or associates degree', |
| "Bachelor's (college) degree or equivalent", |
| "Graduate degree (e.g., Master's degree, MBA)", |
| 'Doctorate degree (e.g., PhD, MD)']) |
| st.session_state.employment = st.radio("What best describes your employment status over the last three months?", |
| ['', 'Working full-time', 'Working part-time', 'Unemployed and looking for work', |
| 'A homemaker or a stay-at-home parent', 'Student', 'Retired', 'Other']) |
|
|
| columns_form = st.columns((1,1,1)) |
| with columns_form[2]: |
| submitted = st.button("Proceed",use_container_width=True, |
| help = 'Make sure you answer every question', |
| disabled = not (all(st.session_state[field] != '' for field in st.session_state.fields) and st.session_state.recycling != 0)) |
|
|
| if submitted: |
|
|
| st.session_state.user_data = {key: st.session_state[key] for key in st.session_state.fields} |
| st.session_state.user_data["model"] = st.session_state["model"] |
| st.session_state.user_data["condition"] = st.query_params['p'] |
| st.session_state.user_data["start_time"] = st.session_state.start_time |
| st.session_state.user_data["inserted"] = st.session_state.inserted |
| st.session_state.user_data["submission_time"] = datetime.now() |
| |
| st.session_state.inserted += 1 |
| st.session_state.submitted = True |
| setup_messages() |
| st.rerun() |
|
|
| if st.session_state.gotit and st.session_state.submitted == False: |
| form() |
| |
| for message in st.session_state.messages: |
| if message['role']!='system': |
| with st.chat_message(message["role"]): |
| st.markdown(message["content"]) |
|
|
| if len(st.session_state.messages) >= st.session_state.max_messages: |
| st.info( |
| "You have reached the limit of messages for this conversation. Please end and submit the conversation." |
| ) |
|
|
| elif st.session_state.submitted == False: |
| pass |
|
|
| elif st.session_state.inserted > 1: |
| st.markdown("## Copy your code!") |
| st.markdown('**Your chatbot code is:**') |
| st.markdown(f'## {st.session_state.user_id}') |
| st.markdown('**Please copy the code and enter it into the survey field below.**') |
|
|
| elif prompt := st.chat_input("Ask a polarizing question..."): |
|
|
| st.session_state.messages.append({"role": "user", "content": prompt}) |
| with st.chat_message("user"): |
| st.markdown(prompt) |
|
|
| with st.chat_message("assistant"): |
| try: |
| stream = client.chat.completions.create( |
| model=st.session_state["model"], |
| messages=[ |
| {"role": m["role"], "content": m["content"]} |
| for m in st.session_state.messages |
| ], |
| stream=True |
| ) |
| |
| response = st.write_stream(stream) |
|
|
| st.session_state.messages.append( |
| {"role": "assistant", "content": response} |
| ) |
| except: |
| rate_limit_message = """ |
| An error has occured or you've reached the maximum conversation length. Please submit the conversation. |
| """ |
| st.session_state.messages.append( |
| {"role": "assistant", "content": rate_limit_message} |
| ) |
| st.session_state.max_messages = len(st.session_state.messages) |
| st.rerun() |
|
|
| if len(st.session_state.messages) > 10 or st.session_state.max_messages == len(st.session_state.messages): |
| columns = st.columns((1,1,1)) |
| with columns[2]: |
| if st.button("Finish",use_container_width=True): |
| keys = ["inserted", "messages", "convo_start_time"] |
|
|
| st.session_state.user_data.update({key: st.session_state[key] for key in keys}) |
| |
| st.session_state.user_data["convo_end_time"] = datetime.now() |
|
|
| with MongoClient(st.secrets["mongo"],server_api=ServerApi('1')) as client: |
| db = client.bridge |
| collection = db.app |
| user_data = st.session_state.user_data |
|
|
| collection.insert_one(user_data) |
| st.session_state.inserted += 1 |
| done = True |
|
|
| setup_messages() |
| st.rerun() |