Yara Kyrychenko commited on
Commit
c0ac814
Β·
1 Parent(s): b9744d4
Files changed (5) hide show
  1. .gitignore +2 -0
  2. .streamlit/config.toml +8 -0
  3. README.md +10 -6
  4. app.py +257 -0
  5. 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: gray
5
- colorTo: yellow
6
  sdk: streamlit
7
- sdk_version: 1.44.0
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
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