DragandDropGroup commited on
Commit
9812b6a
·
verified ·
1 Parent(s): 1d80db3

Add src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +289 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,291 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import requests
3
+ import json
4
+ import web3
5
 
6
+ abi = [{"anonymous":False,"inputs":[{"indexed":False,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"Store","type":"event"},{"inputs":[],"name":"getHashes","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"storeHash","outputs":[],"stateMutability":"nonpayable","type":"function"}]
7
+ # function that uploads the results to ipfs
8
+ def upload_json_to_ipfs(data):
9
+ try:
10
+ url = "https://api.pinata.cloud/pinning/pinJSONToIPFS"
11
+
12
+ print("starting upload to ipfs")
13
+
14
+ # check for JWT secret
15
+ if "PinataJWT" not in st.secrets:
16
+ st.write("No JWT secret found, please add your JWT in a secret titled \"PinataJWT\"")
17
+ return
18
+
19
+ jwt_token = st.secrets["PinataJWT"].strip()
20
+ headers = {
21
+ "Authorization": f"Bearer {jwt_token}",
22
+ "Content-Type": "application/json"
23
+ }
24
+
25
+ # Convert Python dictionary to JSON string
26
+ response = requests.post(url, headers=headers, json=data)
27
+
28
+ if response.status_code == 200:
29
+ # Print the IPFS hash from the successful response
30
+ ipfs_hash = response.json().get("IpfsHash")
31
+ return ipfs_hash
32
+ else:
33
+ st.write(f"Failed to upload JSON. Status code: {response.status_code}")
34
+ st.write(response.text)
35
+ return None
36
+ except Exception as e:
37
+ st.write(f"Error uploading to Pinata: {e}")
38
+
39
+ # function that uploads to blockchain
40
+ def upload_to_blockchain(hash):
41
+ print("starting blockchain upload")
42
+ w3 = web3.Web3(web3.HTTPProvider(st.secrets["infura"]))
43
+
44
+ # create an instance of our contract
45
+ contract = w3.eth.contract(address=st.secrets["ContractAddress"], abi = abi)
46
+
47
+ # Call your function: 11155111 is Sepolia's id
48
+ call_function = contract.functions.storeHash(hash).build_transaction({"chainId": 11155111,
49
+ "from": st.secrets["EthWallet"],
50
+ "nonce": w3.eth.get_transaction_count(st.secrets["EthWallet"])})
51
+
52
+ # Sign transaction
53
+ signed_tx = w3.eth.account.sign_transaction(call_function, private_key=st.secrets["pk"])
54
+
55
+ # Send transaction
56
+ send_tx = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
57
+
58
+ # Wait for transaction receipt
59
+ tx_receipt = w3.eth.wait_for_transaction_receipt(send_tx)
60
+
61
+ print("ETH Hash:")
62
+ print(tx_receipt.logs[0].transactionHash.hex())
63
+
64
+ return tx_receipt.logs[0].transactionHash.hex()
65
+
66
+ def get_ipfs_hashes():
67
+ w3 = web3.Web3(web3.HTTPProvider(st.secrets["infura"]))
68
+
69
+ # Create an instance of the contract
70
+ contract = w3.eth.contract(address=st.secrets["ContractAddress"], abi=abi)
71
+
72
+ # Call the getHashes function
73
+ try:
74
+ ipfs_hashes = contract.functions.getHashes().call()
75
+ return ipfs_hashes
76
+ except Exception as e:
77
+ st.write(f"Error retrieving hashes: {e}")
78
+ return []
79
+
80
+ def retreive_ipfs_hash_data(hashes):
81
+ results = []
82
+ for ipfs_hash in hashes:
83
+ url = f"https://gateway.pinata.cloud/ipfs/{ipfs_hash}"
84
+ try:
85
+ response = requests.get(url)
86
+ if response.status_code == 200:
87
+ data = response.json()
88
+ results.append({"hash": ipfs_hash, "data": data})
89
+ else:
90
+ results.append({"hash": ipfs_hash, "error": f"Failed to retrieve data (status {response.status_code})"})
91
+ except Exception as e:
92
+ results.append({"hash": ipfs_hash, "error": str(e)})
93
+ return results
94
+
95
+
96
+ # function that handles survey submission
97
+ # sets up ipfs and blockchain
98
+ def submission(survey_data):
99
+ ipfs_hash = upload_json_to_ipfs(survey_data)
100
+ if ipfs_hash:
101
+ print("IPFS Upload Successful")
102
+ print(ipfs_hash)
103
+ upload_to_blockchain(ipfs_hash)
104
+ total_number_pages = 4
105
+ placeholder_buttons = None
106
+
107
+ Q1_radio_options = ["Pizza","Burgers","Pasta","Hot Dogs"]
108
+ Q2_radio_options = ["Water","Soda","Coffee","Tea"]
109
+ Q3_radio_options = ["Yes","No"]
110
+ Q4_radio_options = ["N/A", "Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]
111
+
112
+
113
+ # Function that records radio element changes
114
+ def radio_change(element, state, key):
115
+ st.session_state[state] = element.index(st.session_state[key]) # Setting previously selected option
116
+
117
+ def multi_change(element, state, key):
118
+ st.session_state[state] = []
119
+ for selected_option in st.session_state[key]:
120
+ st.session_state[state].append(selected_option)
121
+
122
+ # Function that disables the last button while data is uploaded to IPFS
123
+ def button_disable():
124
+ st.session_state['disabled'] = True
125
+
126
+ def answer_change(state, key):
127
+ st.session_state[state] = st.session_state[key]
128
+
129
+ st.set_page_config(page_title='IPFS-Based Survey',)
130
+ st.title('Survey Test')
131
+
132
+ st.markdown("<style>.row-widget.stButton {text-align: center;}</style>", unsafe_allow_html=True)
133
+ st.markdown("<style>.big-font {font-size:24px;}</style>", unsafe_allow_html=True)
134
+
135
+
136
+ if "current_page" not in st.session_state:
137
+ st.session_state["current_page"] = 1
138
+ st.session_state["Q1"] = None
139
+ st.session_state["Q2"] = None
140
+ st.session_state["Q3"] = None
141
+ st.session_state["Q4"] = None
142
+ st.session_state["Q5"] = None
143
+ st.session_state["disabled"] = False
144
+
145
+ # Page 1; Video
146
+ if st.session_state["current_page"] == 1:
147
+
148
+ st.markdown("""<p class="big-font">This is a description for my survey</p>""", unsafe_allow_html=True)
149
+
150
+ st.radio(label = "What is your favorite food?",
151
+ options = Q1_radio_options,
152
+ index = None if st.session_state["Q1"] == None else st.session_state["Q1"],
153
+ key = 'Q1_radio',
154
+ on_change = radio_change,
155
+ args = (Q1_radio_options, "Q1", "Q1_radio",))
156
+
157
+ st.markdown("""<style> div[class*="stRadio"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 18px;}</style> <br><br>""", unsafe_allow_html=True)
158
+
159
+
160
+ st.multiselect(label = "Select all of the drinks that you like.",
161
+ default = None if st.session_state["Q2"] == None else st.session_state["Q2"],
162
+ options = Q2_radio_options,
163
+ key = 'Q2_multi',
164
+ on_change = multi_change,
165
+ args = (Q2_radio_options, "Q2", "Q2_multi",))
166
+
167
+ st.markdown("""<style> div[class*="stMulti"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 18px;}</style> <br><br>""", unsafe_allow_html=True)
168
+
169
+
170
+ placeholder = st.empty()
171
+
172
+ if st.button('Next', key='next_button_page_1'):
173
+ all_answered = True
174
+ if st.session_state["Q1"] == None or st.session_state["Q1"] == []:
175
+ all_answered = False
176
+ if st.session_state["Q2"] == None or st.session_state["Q2"] == []:
177
+ all_answered = False
178
+ if all_answered:
179
+ st.session_state["current_page"] += 1
180
+ st.rerun()
181
+ else:
182
+ with placeholder.container():
183
+ st.warning("Please answer all the questions on this page.", icon="⚠️")
184
+
185
+ st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")
186
+
187
+
188
+ elif st.session_state["current_page"] == 2:
189
+
190
+ st.video("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
191
+ st.markdown("""<p style='font-size:18px;'>Get rick rolled!</p>""", unsafe_allow_html=True)
192
+ st.selectbox(label = "Was that a good joke?",
193
+ options = Q3_radio_options,
194
+ index = None if st.session_state["Q3"] == None else st.session_state["Q3"],
195
+ key = 'Q3_radio',
196
+ on_change = radio_change,
197
+ args = (Q3_radio_options, "Q3", "Q3_radio",))
198
+
199
+ st.markdown("""<style> div[class*="stSelectbox"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 18px;}</style> <br><br>""", unsafe_allow_html=True)
200
+
201
+
202
+ placeholder = st.empty()
203
+
204
+ col1, col2 = st.columns(2)
205
+ with col1:
206
+ if st.button('Back'):
207
+ st.session_state["current_page"] -= 1
208
+ st.rerun()
209
+ with col2:
210
+ if st.button('Next'):
211
+ all_answered = True
212
+ if st.session_state["Q3"] == None or st.session_state["Q3"] == []:
213
+ all_answered = False
214
+ if all_answered:
215
+ st.session_state["current_page"] += 1
216
+ st.rerun()
217
+ else:
218
+ with placeholder.container():
219
+ st.warning("Please answer all the questions on this page.", icon="⚠️")
220
+
221
+ st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")
222
+
223
+
224
+ elif st.session_state["current_page"] == 3:
225
+
226
+ st.radio(label = "Miami is the best school.", # Likert
227
+ options = Q4_radio_options,
228
+ index = None if st.session_state["Q4"] == None else st.session_state["Q4"],
229
+ key = 'Q4_radio',
230
+ on_change = radio_change,
231
+ args = (Q4_radio_options, "Q4", "Q4_radio",))
232
+
233
+ st.markdown("""<style> div[class*="stRadio"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 18px;}</style> <br><br>""", unsafe_allow_html=True)
234
+
235
+
236
+ if st.session_state["Q5"] == None:
237
+ st.session_state["Q5"] = 50
238
+ st.slider(label="How happy are you today?",min_value=0,max_value=100,
239
+ value= st.session_state["Q5"],
240
+ key = "Q5_slider",
241
+ on_change = answer_change,
242
+ args = ("Q5", "Q5_slider",))
243
+ st.markdown("""<style> div[class*="stSlider"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 18px;}</style> <br><br>""", unsafe_allow_html=True)
244
+
245
+
246
+ placeholder = st.empty()
247
+
248
+ col1, col2 = st.columns(2)
249
+ with col1:
250
+ if st.button('Back'):
251
+ st.session_state["current_page"] -= 1
252
+ st.rerun()
253
+ with col2:
254
+ if st.button('Next'):
255
+ all_answered = True
256
+ if st.session_state["Q4"] == None or st.session_state["Q4"] == []:
257
+ all_answered = False
258
+ if st.session_state["Q5"] == None or st.session_state["Q5"] == []:
259
+ all_answered = False
260
+ if all_answered:
261
+ st.session_state["current_page"] += 1
262
+ st.rerun()
263
+ else:
264
+ with placeholder.container():
265
+ st.warning("Please answer all the questions on this page.", icon="⚠️")
266
+
267
+ st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")
268
+
269
+
270
+ elif st.session_state["current_page"] == 4: # Last Page
271
+ st.markdown('<p class="big-font">Thank you for participating! <br> Click on the button below to submit your answers. </p>', unsafe_allow_html=True)
272
+ st.button('Submit Responses', disabled = st.session_state["disabled"], on_click = button_disable)
273
+ if st.session_state["disabled"]:
274
+ with st.spinner(r"$\textsf{\normalsize Storing data on IPFS and Ethereum. This operation might take a few minutes. Please wait to receive your confirmation code!}$"):
275
+ try:
276
+ response = {
277
+ "Q1": Q1_radio_options[st.session_state["Q1"]],
278
+ "Q2": st.session_state["Q2"],
279
+ "Q3": st.session_state["Q3"],
280
+ "Q4": st.session_state["Q4"],
281
+ "Q5": st.session_state["Q5"],
282
+ }
283
+ submission(response)
284
+ except Exception as e:
285
+ print(e)
286
+ st.error(f'An error ocurred. Here is the error message: {e}', icon="🚨")
287
+
288
+ if st.button('Back'):
289
+ st.session_state["current_page"] -= 1
290
+ st.rerun()
291
+ st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")