Spaces:
Running
Running
Yara Kyrychenko
commited on
Commit
Β·
c0ac814
1
Parent(s):
b9744d4
upd
Browse files- .gitignore +2 -0
- .streamlit/config.toml +8 -0
- README.md +10 -6
- app.py +257 -0
- requirements.txt +3 -0
.gitignore
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
*.DS_Store
|
2 |
+
.streamlit/secrets.toml
|
.streamlit/config.toml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[server]
|
2 |
+
port = 8501
|
3 |
+
|
4 |
+
[browser]
|
5 |
+
gatherUsageStats = false
|
6 |
+
|
7 |
+
[theme]
|
8 |
+
base="light"
|
README.md
CHANGED
@@ -1,12 +1,16 @@
|
|
1 |
---
|
2 |
-
title: Search
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
-
colorTo:
|
6 |
sdk: streamlit
|
7 |
-
sdk_version: 1.
|
8 |
app_file: app.py
|
9 |
pinned: false
|
|
|
10 |
---
|
11 |
|
12 |
-
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
title: Climate Action Search
|
3 |
+
emoji: π
|
4 |
+
colorFrom: red
|
5 |
+
colorTo: green
|
6 |
sdk: streamlit
|
7 |
+
sdk_version: 1.40.0
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
+
license: mit
|
11 |
---
|
12 |
|
13 |
+
|
14 |
+
# Climate Action Search
|
15 |
+
|
16 |
+
Let's search climate action!
|
app.py
ADDED
@@ -0,0 +1,257 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import requests
|
3 |
+
from pymongo.mongo_client import MongoClient
|
4 |
+
from pymongo.server_api import ServerApi
|
5 |
+
from datetime import datetime
|
6 |
+
import time
|
7 |
+
import webbrowser
|
8 |
+
import random
|
9 |
+
|
10 |
+
st.set_page_config(
|
11 |
+
page_title="Climate Action",
|
12 |
+
page_icon="π",
|
13 |
+
initial_sidebar_state="expanded",
|
14 |
+
layout="wide"
|
15 |
+
)
|
16 |
+
st.markdown(
|
17 |
+
""" <style>
|
18 |
+
div[role="radiogroup"] > :first-child{
|
19 |
+
display: none !important;
|
20 |
+
}
|
21 |
+
</style>
|
22 |
+
""",
|
23 |
+
unsafe_allow_html=True
|
24 |
+
)
|
25 |
+
|
26 |
+
### Setting up the session state
|
27 |
+
|
28 |
+
if 'inserted' not in st.session_state:
|
29 |
+
st.session_state["model"] = "google"
|
30 |
+
# web app state
|
31 |
+
st.session_state.gotit = False
|
32 |
+
st.session_state.submitted = False
|
33 |
+
st.session_state.inserted = 0
|
34 |
+
st.session_state.max_messages = 50
|
35 |
+
st.session_state.clicked_links = []
|
36 |
+
st.session_state.messages = [{"query": "", "results": {}, "page": 1, "time": datetime.now()}]
|
37 |
+
st.session_state.user_data = {}
|
38 |
+
|
39 |
+
# user info state
|
40 |
+
st.session_state.fields = [
|
41 |
+
'climate_actions', 'age', 'gender', 'education', 'residence', 'property', 'car',
|
42 |
+
'politics', 'impact_open', 'ev',
|
43 |
+
'fossil', 'aerosol', 'diet', 'recycling',
|
44 |
+
'user_id'
|
45 |
+
]
|
46 |
+
|
47 |
+
for field in st.session_state.fields:
|
48 |
+
st.session_state[field] = ''
|
49 |
+
|
50 |
+
st.session_state.user_id = str(random.randint(100000, 999999))
|
51 |
+
|
52 |
+
st.session_state.recycling = 0
|
53 |
+
|
54 |
+
st.session_state.start_time = datetime.now()
|
55 |
+
st.session_state.convo_start_time = ''
|
56 |
+
|
57 |
+
RESULTS_PER_PAGE = 10
|
58 |
+
if "page" not in st.session_state:
|
59 |
+
st.session_state.page = 1
|
60 |
+
if 'p' not in st.query_params:
|
61 |
+
st.query_params['p'] = 'g'
|
62 |
+
|
63 |
+
### App interface
|
64 |
+
with st.sidebar:
|
65 |
+
st.markdown("# Let's talk climate action!")
|
66 |
+
st.markdown(f"""
|
67 |
+
{"β" if st.session_state.submitted else "β"} **Step 1. Complete a form.**
|
68 |
+
|
69 |
+
{"β" if len(st.session_state.messages) > 1 else "β"} **Step 2. Type in the search box to search Google**
|
70 |
+
|
71 |
+
π± You should ask a climate change related question like:
|
72 |
+
- *What are the most effective actions to reduce my carbon emissions?*
|
73 |
+
- *What's better for the environment: a year of vegetarianism or skipping one transatlantic flight?*
|
74 |
+
- *How do the emissions saved by switching to an EV compare to recycling for a year in terms of trees planted?*
|
75 |
+
|
76 |
+
β **Do not share any personal information (e.g., name or address) in the chat.**
|
77 |
+
|
78 |
+
β οΈ You must click on **at least 5 links** before you can submit the search. An *End Search* button will appear then. You can continue before submitting, but **you must submit the conversation to receive compensation**.
|
79 |
+
|
80 |
+
{"β" if st.session_state.inserted > 1 else "β"} **Step 3. Use the *End Search* button to submit your response.**
|
81 |
+
|
82 |
+
**Do not forget to copy & paste your completion code!**
|
83 |
+
|
84 |
+
βΊ *You can always return to this panel by clicking the arrow on the top left.*
|
85 |
+
|
86 |
+
{"π **All done! Please press *Next* in the survey.**" if st.session_state.inserted > 1 else ""}
|
87 |
+
""")
|
88 |
+
if st.session_state.gotit == False or st.session_state.submitted == False:
|
89 |
+
st.session_state.gotit = st.button("Let's start!", key=None, help=None, use_container_width=True)
|
90 |
+
|
91 |
+
@st.cache_data
|
92 |
+
def google_search(query, page):
|
93 |
+
start_index = (page - 1) * RESULTS_PER_PAGE + 1 # Google API uses 1-based index
|
94 |
+
url = f"https://www.googleapis.com/customsearch/v1?q={query}&key={st.secrets['GOOGLE_API_KEY']}&cx={st.secrets['GOOGLE_CX']}&start={start_index}"
|
95 |
+
response = requests.get(url)
|
96 |
+
return response.json()
|
97 |
+
|
98 |
+
def display_results(results):
|
99 |
+
for item in results.get('items', []):
|
100 |
+
col1, col2 = st.columns([1, 5], vertical_alignment='center')
|
101 |
+
|
102 |
+
|
103 |
+
image_url = None
|
104 |
+
if "pagemap" in item and "cse_thumbnail" in item["pagemap"]:
|
105 |
+
image_url = item["pagemap"]["cse_thumbnail"][0]["src"]
|
106 |
+
|
107 |
+
with col1:
|
108 |
+
if image_url:
|
109 |
+
st.image(image_url, width=160)
|
110 |
+
|
111 |
+
with col2:
|
112 |
+
#st.markdown(f"**{item['title']}**")
|
113 |
+
#st.markdown(item['snippet'])
|
114 |
+
|
115 |
+
if st.button(f"π **{item['title']}**", item['link'], type='tertiary'):
|
116 |
+
st.session_state.clicked_links.append(item['link'])
|
117 |
+
webbrowser.open(item['link'])
|
118 |
+
st.markdown(item['snippet'])
|
119 |
+
|
120 |
+
|
121 |
+
st.divider()
|
122 |
+
|
123 |
+
@st.dialog('Form', width="large")
|
124 |
+
def form():
|
125 |
+
st.markdown("**β Please answer every question to proceed.**")
|
126 |
+
st.session_state.age = st.text_input("How old are you in years?")
|
127 |
+
st.session_state.gender = st.radio("Do you describe yourself as a man, a woman, or in some other way?",
|
128 |
+
['','Man', 'Woman', 'Other'])
|
129 |
+
st.session_state.education = st.radio("What is the highest level of education you completed?",
|
130 |
+
['',
|
131 |
+
'Did not graduate high school',
|
132 |
+
'High school graduate, GED, or alternative',
|
133 |
+
'Some college, or associates degree',
|
134 |
+
"Bachelor's (college) degree or equivalent",
|
135 |
+
"Graduate degree (e.g., Master's degree, MBA)",
|
136 |
+
'Doctorate degree (e.g., PhD, MD)'])
|
137 |
+
st.session_state.politics = st.radio('What is your political orientation?', ['', 'Extremely liberal', 'Liberal', 'Slightly liberal', 'Moderate', 'Slightly conservative', 'Conservative', 'Extremely conservative'])
|
138 |
+
st.session_state.residence = st.radio("What type of a community do you live in?",
|
139 |
+
['', 'Urban','Suburban','Rural','Other'])
|
140 |
+
st.session_state.property = st.radio("Do you own or rent the home in which you live?",
|
141 |
+
['', 'Own', 'Rent', 'Neither (I live rent-free)', 'Other' ])
|
142 |
+
st.session_state.car = st.radio("Do you own or lease a car?",
|
143 |
+
['', 'Own', 'Lease', 'Neither (I do not own or lease a car)'])
|
144 |
+
|
145 |
+
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.')
|
146 |
+
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?')
|
147 |
+
|
148 |
+
st.session_state.recycling = st.slider('What percentage of plastic produced gets recycled?', 0, 100, value=0)
|
149 |
+
|
150 |
+
st.markdown("**Do you agree or disagree with the following statements?**")
|
151 |
+
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"])
|
152 |
+
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"])
|
153 |
+
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"])
|
154 |
+
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"])
|
155 |
+
|
156 |
+
|
157 |
+
columns_form = st.columns((1,1,1))
|
158 |
+
with columns_form[2]:
|
159 |
+
submitted = st.button("Proceed",use_container_width=True,
|
160 |
+
help = 'Make sure you answer every question',
|
161 |
+
disabled = not (all(st.session_state[field] != '' for field in st.session_state.fields) and st.session_state.recycling != 0))
|
162 |
+
|
163 |
+
if submitted:
|
164 |
+
|
165 |
+
st.session_state.user_data = {key: st.session_state[key] for key in st.session_state.fields}
|
166 |
+
st.session_state.user_data["model"] = st.session_state["model"]
|
167 |
+
st.session_state.user_data["condition"] = st.query_params['p']
|
168 |
+
st.session_state.user_data["start_time"] = st.session_state.start_time
|
169 |
+
st.session_state.user_data["inserted"] = st.session_state.inserted
|
170 |
+
st.session_state.user_data["submission_time"] = datetime.now()
|
171 |
+
|
172 |
+
with MongoClient(st.secrets["mongo"],server_api=ServerApi('1')) as client:
|
173 |
+
db = client.chat
|
174 |
+
collection = db.app
|
175 |
+
user_data = st.session_state.user_data
|
176 |
+
collection.insert_one(user_data)
|
177 |
+
st.session_state.inserted += 1
|
178 |
+
st.session_state.submitted = True
|
179 |
+
st.rerun()
|
180 |
+
|
181 |
+
if st.session_state.gotit and st.session_state.submitted == False:
|
182 |
+
form()
|
183 |
+
|
184 |
+
@st.dialog('Submit', width="large")
|
185 |
+
def submit():
|
186 |
+
st.markdown("You must answer all questions marked with a β to submit.")
|
187 |
+
if st.query_params["p"] != "n":
|
188 |
+
st.slider('β How would you rate the conversation on a scale from *Terrible* to *Perfect*?', 0, 100, format="", key="score", value=50)
|
189 |
+
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)
|
190 |
+
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)
|
191 |
+
else:
|
192 |
+
st.session_state.score = 0
|
193 |
+
st.session_state.personalization_score = 0
|
194 |
+
st.session_state.knowledge_score = 0
|
195 |
+
|
196 |
+
st.text_area('Any feedback?',key="feedback")
|
197 |
+
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):
|
198 |
+
keys = ["score", "personalization_score", "knowledge_score",
|
199 |
+
"feedback",
|
200 |
+
"inserted", "messages", "convo_start_time", 'clicked_links']
|
201 |
+
|
202 |
+
st.session_state.user_data.update({key: st.session_state[key] for key in keys})
|
203 |
+
|
204 |
+
st.session_state.user_data["convo_end_time"] = datetime.now()
|
205 |
+
|
206 |
+
with MongoClient(st.secrets["mongo"],server_api=ServerApi('1')) as client:
|
207 |
+
db = client.chat
|
208 |
+
collection = db.app
|
209 |
+
user_data = st.session_state.user_data
|
210 |
+
del user_data['_id']
|
211 |
+
|
212 |
+
collection.insert_one(user_data)
|
213 |
+
st.session_state.inserted += 1
|
214 |
+
|
215 |
+
st.rerun()
|
216 |
+
|
217 |
+
if len(st.session_state.messages) >= st.session_state.max_messages:
|
218 |
+
st.info(
|
219 |
+
"You have reached the limit of searches for this search. Please end and submit the search."
|
220 |
+
)
|
221 |
+
|
222 |
+
elif st.session_state.submitted == False:
|
223 |
+
pass
|
224 |
+
|
225 |
+
elif st.session_state.inserted > 1:
|
226 |
+
st.markdown("## Copy your code!")
|
227 |
+
st.markdown('**Your completion code is:**')
|
228 |
+
st.markdown(f'## {st.session_state.user_id}')
|
229 |
+
st.markdown('**Please copy the code and enter it into the survey field below.**')
|
230 |
+
|
231 |
+
elif query := st.text_input("Enter search query and press Enter β", placeholder="Search Google..."):
|
232 |
+
|
233 |
+
if query != st.session_state.messages[-1]["query"] or st.session_state.page != st.session_state.messages[-1]["page"]:
|
234 |
+
results = google_search(query, st.session_state.page)
|
235 |
+
st.session_state.messages.append({"query": query, "results": results, "page": st.session_state.page, "time": datetime.now()})
|
236 |
+
|
237 |
+
display_results(st.session_state.messages[-1]["results"])
|
238 |
+
|
239 |
+
col1, _, col2 = st.columns([.2, .6, .2])
|
240 |
+
with col1:
|
241 |
+
if st.session_state.page > 1: # Show "Previous" button only if not on first page
|
242 |
+
if st.button("β¬
οΈ Previous Page",use_container_width=True):
|
243 |
+
st.session_state.page -= 1
|
244 |
+
st.rerun()
|
245 |
+
|
246 |
+
with col2:
|
247 |
+
if "nextPage" in st.session_state.messages[-1]["results"].get("queries", {}): # Check if next page exists
|
248 |
+
if st.button("Next Page β‘οΈ",use_container_width=True):
|
249 |
+
st.session_state.page += 1
|
250 |
+
st.rerun()
|
251 |
+
|
252 |
+
if (len(st.session_state.clicked_links) > 4 or st.session_state.max_messages == len(st.session_state.messages)) and not st.session_state.inserted > 1:
|
253 |
+
columns = st.columns((1,1,1))
|
254 |
+
with columns[2]:
|
255 |
+
if st.button("End Search",use_container_width=True):
|
256 |
+
submit()
|
257 |
+
|
requirements.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
streamlit==1.44.0
|
2 |
+
pymongo[srv]==4.11 #3.12
|
3 |
+
datetime==5.5
|