Spaces:
Running
Running
import streamlit as st | |
#from openai import OpenAI | |
from together import Together | |
from datetime import datetime | |
import time | |
st.set_page_config( | |
page_title="Chat with me!", | |
page_icon="π", | |
initial_sidebar_state="expanded", | |
layout="wide" | |
) | |
st.markdown( | |
""" <style> | |
div[role="radiogroup"] > :first-child{ | |
display: none !important; | |
} | |
</style> | |
""", | |
unsafe_allow_html=True | |
) | |
### Setting up the session state | |
def generate_tokens(response): | |
for token in response: | |
if hasattr(token, 'choices') and token.choices: | |
content = token.choices[0].delta.content | |
if content: | |
yield content | |
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: | |
### read in txts | |
with open('base.txt', 'r') as file: | |
st.session_state.base_text = file.read() | |
with open('knowledge.txt', 'r') as file: | |
st.session_state.knowledge_text = file.read() | |
with open('personalization.txt', 'r') as file: | |
st.session_state.personalization_text = file.read() | |
# web app state | |
st.session_state.gotit = False | |
st.session_state.inserted = 0 | |
st.session_state.submitted = False | |
st.session_state["model"] = "deepseek-ai/DeepSeek-V3" | |
st.session_state.max_messages = 50 | |
st.session_state.messages = [] | |
# user info state | |
st.session_state.fields = [ | |
'climate_actions', 'age', 'gender', 'education', 'residence', 'property', | |
'politics', 'impact_open', 'ev', | |
'fossil', 'aerosol', 'diet', 'recycling', | |
'user_id' | |
] | |
for field in st.session_state.fields: | |
st.session_state[field] = '' | |
st.session_state.recycling = 0 | |
# timers | |
st.session_state.start_time = datetime.now() | |
st.session_state.convo_start_time = '' | |
if 'p' not in st.query_params: | |
st.query_params['p'] = 't' | |
def setup_messages(): | |
# t = personalization | |
# k = knowledge | |
# f = formatting | |
# n = no chat | |
if st.query_params["p"] == "f" or st.query_params["p"] == "n": | |
st.session_state.system_message = st.session_state.base_text | |
elif st.query_params["p"] == "k": | |
st.session_state.system_message = st.session_state.knowledge_text | |
elif st.query_params["p"] == "t": | |
st.session_state.system_message = format_personalization(st.session_state.personalization_text) | |
st.session_state.messages = [{ "role": "system", "content": st.session_state.system_message}] | |
st.session_state.convo_start_time = datetime.now() | |
client = Together(api_key=st.secrets["TOGETHER_API_KEY"]) | |
### App interface | |
with st.sidebar: | |
st.markdown("# Let's talk climate action!") | |
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.** | |
You should ask a climate change related question like: | |
- *What are the most effective actions to reduce my carbon emissions?* | |
- *What's better for the environment: a year of vegetarianism or skipping one transatlantic flight?* | |
- *How do the emissions saved by switching to an EV compare to recycling for a year in terms of trees planted?* | |
If you're unsure about a metric or number, simply ask the chatbot for an explanation. | |
You must respond **at least 5 times** before you can submit the conversation. An *End Conversation* button will appear then. You are free to continue the conversation further before you submit it. | |
{"β" if st.session_state.inserted > 0 else "β"} **Step 3. Use the *End Conversation* button to submit your response.** | |
You have to submit your conversation to receive compensation. | |
{"π **All done! Please press *Next* in the survey.**" if st.session_state.inserted > 0 else ""} | |
""") | |
if st.session_state.gotit == False: | |
st.markdown("*You can always return to this panel by clicking the arrow on the top left.*") | |
st.session_state.gotit = st.button("Let's start!", key=None, help=None, use_container_width=True) | |
def form(): | |
st.markdown("**β Please answer every question to proceed.**") | |
st.session_state.user_id = st.text_input(label="Enter your Prolific ID", value=st.session_state.user_id) | |
st.session_state.age = st.text_input("How old are you in years?") | |
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.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.residence = st.radio("What type of a community do you live in?", | |
['', 'Urban','Suburban','Rural','Other']) | |
st.session_state.property = st.radio("Do you own or rent the home in which you live?", | |
['', 'Own','Rent','Neither (I live rent-free)', | |
'Other' ]) | |
st.session_state.politics = st.radio('What is your political orientation?', ['', 'Extremely liberal', 'Liberal', 'Slightly liberal', 'Moderate', 'Slightly conservative', 'Conservative', 'Extremely conservative']) | |
st.session_state.climate_actions = st.text_area('Please describe any actions you are taking to address climate change? Write *None* if you are not taking any.') | |
st.session_state.impact_open = st.text_area('What do you believe is the single most effective action you can take to reduce carbon emissions that contribute to climate change?') | |
st.session_state.recycling = st.slider('What percentage of plastic produced gets recycled?', 0, 100, value=0) | |
st.markdown("**Do you agree or disagree with the following statements?**") | |
st.session_state.ev = st.radio("Electric vehicles don't have enough range to handle daily travel demands.", ["", "Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]) | |
st.session_state.fossil = st.radio('The fossil fuel industry is trying to shift the blame away from themselves by emphasizing the importance of individual climate action.', ["", "Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]) | |
st.session_state.aerosol = st.radio('The use of aerosol spray cans is a major cause of climate change.', ["", "Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]) | |
st.session_state.diet = st.radio('Lab-grown meat produces up to 25 times more CO2 than real meat.', ["", "Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]) | |
columns_form = st.columns((1,1,1)) | |
with columns_form[2]: | |
submitted = st.button("Proceed",use_container_width=True, | |
help = 'Please answer every question and click *Proceed* to start a conversation.', | |
disabled = not (all(st.session_state[field] != '' for field in st.session_state.fields) and st.session_state.recycling != 0)) | |
if submitted: | |
user_data = {key: st.session_state[key] for key in st.session_state.fields} | |
user_data["model"] = st.session_state["model"] | |
user_data["condition"] = st.query_params['p'] | |
user_data["start_time"] = st.session_state.start_time | |
user_data["inserted"] = st.session_state.inserted | |
user_data["submission_time"] = datetime.now() | |
from pymongo.mongo_client import MongoClient | |
from pymongo.server_api import ServerApi | |
with MongoClient(st.secrets["mongo"],server_api=ServerApi('1')) as client: | |
db = client.chat | |
collection = db.app | |
collection.insert_one(user_data) | |
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"]) | |
def submit(): | |
st.markdown("You must answer all questions marked with a β to submit.") | |
if st.query_params["p"] != "n": | |
st.slider('β How would you rate the conversation on a scale from *Terrible* to *Perfect*?', 0, 100, format="", key="score", value=50) | |
st.slider('β How personalized did the conversation feel, on a scale from *Not at all* to *Extremely personalized*?', 0, 100, format="", key="personalization_score", value=50) | |
st.slider('β How knowledgeable do you feel the chatbot was, on a scale from *Not at all* to *Extremely knowledgeable*?', 0, 100, format="", key="knowledge_score", value=50) | |
else: | |
st.session_state.score = 0 | |
st.session_state.personalization_score = 0 | |
st.session_state.knowledge_score = 0 | |
st.text_area('Any feedback?',key="feedback") | |
if st.button('Submit', key=None, help=None, use_container_width=True, disabled=st.session_state.score==50 or st.session_state.personalization_score==50): | |
keys = [ | |
"user_id", "messages", | |
"score", "personalization_score", "knowledge_score", | |
"model", "feedback", | |
"age", "gender", "education", "residence", "property", "politics", | |
"climate_actions", "impact_open", | |
"recycling", "ev", "fossil", "aerosol", "diet", | |
"inserted", "start_time", | |
"convo_start_time" | |
] | |
user_data = {key: st.session_state[key] for key in keys} | |
user_data["condition"] = {st.query_params['p']} | |
user_data["submission_time"] = datetime.now() | |
from pymongo.mongo_client import MongoClient | |
from pymongo.server_api import ServerApi | |
with MongoClient(st.secrets["mongo"],server_api=ServerApi('1')) as client: | |
db = client.chat | |
collection = db.app | |
collection.insert_one(user_data) | |
st.session_state.inserted += 1 | |
st.success('**Your conversation has been submitted! Please proceed with the survey.**', icon="β ") | |
time.sleep(10) | |
setup_messages() | |
st.rerun() | |
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 conversatione." | |
) | |
elif st.session_state.submitted == False: | |
pass | |
elif st.query_params["p"] == "n": | |
st.markdown(""" | |
You have not been selected to have a conversation with the chatbot. | |
β **Please press *End Conversation* to submit your data and proceed with the survey. You have to submit to receive compensation.** | |
""") | |
columns = st.columns((1,1,1)) | |
with columns[2]: | |
if st.button("End Conversation",use_container_width=True): | |
submit() | |
elif prompt := st.chat_input("Ask a question about climate action..."): | |
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 | |
], | |
max_tokens=None, | |
temperature=0.6, | |
top_p=0.7, | |
top_k=50, | |
stop=["<ο½endβofβsentenceο½>"], | |
stream=True | |
) | |
response = st.write_stream(generate_tokens(stream)) | |
print(response) | |
st.session_state.messages.append( | |
{"role": "assistant", "content": response} | |
) | |
except: | |
st.session_state.max_messages = len(st.session_state.messages) | |
rate_limit_message = """ | |
Oops! Sorry, I can't talk now. Too many people have used | |
this service recently. | |
""" | |
st.session_state.messages.append( | |
{"role": "assistant", "content": rate_limit_message} | |
) | |
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("End Conversation",use_container_width=True): | |
submit() | |