Spaces:
Running
Running
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="Climate Action", | |
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 deepseek | |
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: | |
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.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 = {} | |
# user info state | |
st.session_state.fields = [ | |
'climate_actions', 'age', 'gender', 'education', 'residence', 'property', 'car', | |
'politics', 'impact_open', 'ev', | |
'fossil', 'aerosol', 'diet', 'recycling', | |
'user_id' | |
] | |
for field in st.session_state.fields: | |
st.session_state[field] = '' | |
st.session_state.user_id = str(random.randint(100000, 999999)) | |
st.session_state.recycling = 0 | |
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 = OpenAI( base_url="https://openrouter.ai/api/v1", api_key=st.secrets["OPENROUTER_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?* | |
β 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 completion 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 completion code** | |
β οΈ Do not forget to copy & paste your completion code! | |
βΊ You can always return to this panel by clicking the arrow on the top left. | |
{"π **All done! Please enter your code in the survye 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) | |
def form(): | |
st.markdown("**Please answer every question to proceed.**") | |
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.politics = st.radio('What is your political orientation?', ['', 'Extremely liberal', 'Liberal', 'Slightly liberal', 'Moderate', 'Slightly conservative', 'Conservative', 'Extremely conservative']) | |
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.car = st.radio("Do you own or lease a car?", | |
['', 'Own', 'Lease', 'Neither (I do not own or lease a car)']) | |
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 = '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() | |
#with MongoClient(st.secrets["mongo"],server_api=ServerApi('1')) as client: | |
# db = client.chat | |
# collection = db.app | |
# user_data = st.session_state.user_data | |
# 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"]) | |
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 completion 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 st.query_params["p"] == "n": | |
st.markdown("""**You have not been selected to have a conversation with the chatbot.** | |
Please press *Finish* to get your completion code. | |
""") | |
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.chat | |
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() | |
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 | |
], | |
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.chat | |
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() | |