adollbo commited on
Commit
6877f18
·
1 Parent(s): 54210c2

fixed bug for sending changed input, added comments

Browse files
Files changed (1) hide show
  1. app.py +187 -67
app.py CHANGED
@@ -2,10 +2,26 @@ import streamlit as st
2
  import pandas as pd
3
  import logging
4
  from deeploy import Client
5
- from utils import get_request_body, get_fake_certainty, get_model_url, get_random_suspicious_transaction
6
- from utils import get_explainability_texts, get_explainability_values, send_evaluation, get_comment_explanation
 
 
 
 
 
 
 
 
 
 
7
  from utils import COL_NAMES, feature_texts
8
- from utils import create_data_input_table, create_table, ChangeButtonColour, get_weights, modify_datapoint
 
 
 
 
 
 
9
 
10
  logging.basicConfig(level=logging.INFO)
11
 
@@ -14,35 +30,78 @@ st.set_page_config(layout="wide")
14
  st.title("Smart AML:tm:")
15
  st.divider()
16
 
 
17
  data = pd.read_pickle("data/preprocessed_data.pkl")
18
 
19
- if 'predict_button_clicked' not in st.session_state:
 
20
  st.session_state.predict_button_clicked = False
21
 
22
-
23
  if "submitted_disabled" not in st.session_state:
24
  st.session_state.submitted_disabled = False
25
 
26
  if "disabled" not in st.session_state:
27
  st.session_state.disabled = False
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  def disabled():
30
  st.session_state.disabled = True
31
 
 
 
32
  def rerun():
33
  st.session_state.predict_button_clicked = True
34
  st.session_state.submitted_disabled = False
 
 
 
 
35
 
 
36
  def submitted_disabled():
37
  st.session_state.submitted_disabled = True
38
 
39
- st.markdown("""
 
 
 
40
  <style>
41
  [data-testid=stSidebar] {
42
  background-color: #E0E0E0; ##E5E6EA
43
  }
44
  </style>
45
- """, unsafe_allow_html=True)
 
 
46
 
47
  with st.sidebar:
48
  # Add deeploy logo
@@ -50,34 +109,41 @@ with st.sidebar:
50
  # Ask for model URL and token
51
  host = st.text_input("Host (changing is optional)", "app.deeploy.ml")
52
  model_url, workspace_id, deployment_id = get_model_url()
53
- deployment_token = st.text_input("Deeploy Model Token", "my-secret-token") # my-secret-token
54
  if deployment_token == "my-secret-token":
55
- st.warning(
56
- "Please enter Deeploy API token."
 
 
 
 
 
 
 
 
57
  )
58
- else:
59
- st.button("Get suspicious transaction", key="predict_button", help="Click to get a suspicious transaction", use_container_width=True, on_click=disabled, disabled=st.session_state.disabled
60
- ) #on_click=lambda: st.experimental_rerun()
61
- ChangeButtonColour("Get suspicious transaction", '#FFFFFF', "#00052D")#'#FFFFFF', "#00052D"
62
-
63
 
64
- # define client optsions and instantiate client
65
  client_options = {
66
- "host": host,
67
- "deployment_token": deployment_token,
68
- "workspace_id": workspace_id,
69
  }
70
  client = Client(**client_options)
71
 
72
- if 'predict_button' not in st.session_state:
 
 
73
  st.session_state.predict_button = False
74
 
75
- if st.session_state.predict_button: # and not st.session_state.predict_button_clicked
76
  st.session_state.predict_button_clicked = True
77
 
78
- if 'got_explanation' not in st.session_state:
79
  st.session_state.got_explanation = False
80
 
 
81
  if st.session_state.predict_button_clicked:
82
  try:
83
  with st.spinner("Loading..."):
@@ -85,9 +151,7 @@ if st.session_state.predict_button_clicked:
85
  request_body = get_request_body(datapoint_pd)
86
  # Call the explain endpoint as it also includes the prediction
87
  exp = client.explain(request_body=request_body, deployment_id=deployment_id)
88
- # request_log_id = exp["requestLogId"]
89
- # prediction_log_id = exp["predictionLogIds"][0]
90
- st.session_state.shap_values = exp['explanations'][0]['shap_values']
91
  st.session_state.request_log_id = exp["requestLogId"]
92
  st.session_state.prediction_log_id = exp["predictionLogIds"][0]
93
  st.session_state.datapoint_pd = datapoint_pd
@@ -103,10 +167,13 @@ if st.session_state.predict_button_clicked:
103
  + "Contact Deeploy if the problem persists."
104
  )
105
 
 
106
  if not st.session_state.got_explanation:
107
- st.info(
108
  "Fill in left hand side and click on button to observe a potential fraudulent transaction"
109
- )
 
 
110
  if st.session_state.got_explanation:
111
  shap_values = st.session_state.shap_values
112
  request_log_id = st.session_state.request_log_id
@@ -115,80 +182,133 @@ if st.session_state.got_explanation:
115
  certainty = st.session_state.certainty
116
  datapoint = modify_datapoint(datapoint_pd)
117
 
 
118
  col1, col2 = st.columns(2)
119
 
 
120
  with col1:
121
  create_data_input_table(datapoint, COL_NAMES)
122
 
 
123
  with col2:
124
- st.subheader('AML Model Hit')
125
- # st.success(f'{certainty}')
126
- # st.metric(label='Model Certainty', value=certainty)
127
- # style_metric_cards(border_left_color='#00052D', box_shadow=False)
128
- # # st.markdown('#### Model Certainty')
129
- st.metric(label='Model Certainty', value=certainty, delta='threshold: 75%')
130
-
131
-
132
- explainability_texts, sorted_indices = get_explainability_texts(shap_values, feature_texts)
133
  weights = get_weights(shap_values, sorted_indices)
134
  explainability_values = get_explainability_values(sorted_indices, datapoint)
135
- create_table(explainability_texts, explainability_values, weights, 'Important Suspicious Factors')
 
 
 
 
 
136
 
137
  st.subheader("")
138
- # st.markdown("<h2 style='text-align: center; white: red;'>Evaluation</h2>", unsafe_allow_html=True)
139
-
140
- if 'eval_selected' not in st.session_state:
141
- st.session_state['eval_selected'] = False
142
 
 
 
 
143
 
 
144
  col3, col4 = st.columns(2)
 
 
145
  with col3:
 
146
  eval1 = st.empty()
147
- eval1.button("Send to FIU", key="yes_button", use_container_width=True, disabled=st.session_state.submitted_disabled)
148
- ChangeButtonColour("Send to FIU", '#FFFFFF', '#4C506C') #'#FFFFFF', "#DD360C"
 
 
 
 
 
149
  st.session_state.yes_button_clicked = False
150
 
151
  if st.session_state.yes_button:
152
  st.session_state.eval_selected = True
153
- st.session_state.evaluation_input = {
154
- "result": 0 # Agree with the prediction
155
- }
156
-
157
  with col4:
 
158
  eval2 = st.empty()
159
- eval2.button("Not money laundering", key="no_button", use_container_width=True, disabled=st.session_state.submitted_disabled)
160
- ChangeButtonColour("Not money laundering", '#FFFFFF', '#4C506C') # '#FFFFFF', "#46B071", '#FFFFFF', "#666666"
 
 
 
 
 
161
  st.session_state.no_button_clicked = False
162
-
163
-
164
  if st.session_state.no_button:
165
  st.session_state.no_button_clicked = True
166
  if st.session_state.no_button_clicked:
167
  st.session_state.eval_selected = True
168
- desired_output = 1
169
  st.session_state.evaluation_input = {
170
- "result": 1, # Disagree with the prediction
171
- "value": {"predictions": [desired_output]},
172
  }
173
 
 
174
  success = False
175
  if st.session_state.eval_selected:
176
- # st.write('after eval')
177
- # st.write(st.session_state)
178
  if st.session_state.yes_button:
179
- explanation = get_comment_explanation(certainty, explainability_texts, explainability_values)
180
- comment = st.text_area("Reason for evaluation:", explanation)
181
- st.session_state.evaluation_input["explanation"] = comment
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  if st.session_state.no_button:
183
- comment = st.text_area("Reason for evaluation:", "I don't think this transaction is money laundering because...")
184
- st.session_state.evaluation_input["explanation"] = comment
185
- logging.debug("Selected feedback:" + str(st.session_state.evaluation_input))
 
 
 
 
 
 
 
186
  eval3 = st.empty()
187
- eval3.button("Submit", key="submit_button", use_container_width=True, on_click=submitted_disabled, disabled=st.session_state.submitted_disabled)
188
- ChangeButtonColour("Submit", '#FFFFFF', "#00052D")
 
 
 
 
 
 
 
 
189
  if st.session_state.submit_button:
190
  st.session_state.eval_selected = False
191
- success = send_evaluation(client, deployment_id, request_log_id, prediction_log_id, st.session_state.evaluation_input)
 
 
 
 
 
 
 
 
192
  if success:
193
  st.session_state.eval_selected = False
194
  st.session_state.submitted = True
@@ -196,5 +316,5 @@ if st.session_state.got_explanation:
196
  eval2.empty()
197
  eval3.empty()
198
  st.warning("Feedback submitted successfully")
199
- st.button("Next", key='next', use_container_width=True, on_click=rerun)
200
- ChangeButtonColour("Next", '#FFFFFF', "#00052D") #'#FFFFFF', #F9B917" "#DD360C #457EA4
 
2
  import pandas as pd
3
  import logging
4
  from deeploy import Client
5
+ from utils import (
6
+ get_request_body,
7
+ get_fake_certainty,
8
+ get_model_url,
9
+ get_random_suspicious_transaction,
10
+ )
11
+ from utils import (
12
+ get_explainability_texts,
13
+ get_explainability_values,
14
+ send_evaluation,
15
+ get_comment_explanation,
16
+ )
17
  from utils import COL_NAMES, feature_texts
18
+ from utils import (
19
+ create_data_input_table,
20
+ create_table,
21
+ ChangeButtonColour,
22
+ get_weights,
23
+ modify_datapoint,
24
+ )
25
 
26
  logging.basicConfig(level=logging.INFO)
27
 
 
30
  st.title("Smart AML:tm:")
31
  st.divider()
32
 
33
+ # Import data
34
  data = pd.read_pickle("data/preprocessed_data.pkl")
35
 
36
+ # instantiate important vars in session state
37
+ if "predict_button_clicked" not in st.session_state:
38
  st.session_state.predict_button_clicked = False
39
 
 
40
  if "submitted_disabled" not in st.session_state:
41
  st.session_state.submitted_disabled = False
42
 
43
  if "disabled" not in st.session_state:
44
  st.session_state.disabled = False
45
 
46
+ if "no_button_text" not in st.session_state:
47
+ st.session_state.no_button_text = (
48
+ "I don't think this transaction is money laundering because..."
49
+ )
50
+
51
+ if "yes_button_text" not in st.session_state:
52
+ st.session_state.yes_button_text = ""
53
+
54
+ if "yes_button_clicked" not in st.session_state:
55
+ st.session_state.yes_button_clicked = False
56
+
57
+
58
+ # define functions to be run when buttons are clicked
59
+ # func to be run when input changes in no button text area
60
+ def get_input_no_button():
61
+ st.session_state.no_button_text = comment.replace(
62
+ st.session_state.no_button_text, st.session_state.no_comment
63
+ )
64
+ st.session_state.evaluation_input["explanation"] = st.session_state.no_button_text
65
+
66
+
67
+ # func to be run when input changes in yes button text area
68
+ def get_input_yes_button():
69
+ st.session_state.yes_button_text = comment.replace(
70
+ st.session_state.yes_button_text, st.session_state.yes_comment
71
+ )
72
+ st.session_state.evaluation_input["explanation"] = st.session_state.yes_button_text
73
+
74
+
75
+ # func to disable click again for button "Get suspicious transactions"
76
  def disabled():
77
  st.session_state.disabled = True
78
 
79
+
80
+ # func for Next button to rerun and get new prediction
81
  def rerun():
82
  st.session_state.predict_button_clicked = True
83
  st.session_state.submitted_disabled = False
84
+ st.session_state.no_button_text = (
85
+ "I don't think this transaction is money laundering because..."
86
+ )
87
+
88
 
89
+ # func for submit button to disable resubmit
90
  def submitted_disabled():
91
  st.session_state.submitted_disabled = True
92
 
93
+
94
+ # color specs for sidebar
95
+ st.markdown(
96
+ """
97
  <style>
98
  [data-testid=stSidebar] {
99
  background-color: #E0E0E0; ##E5E6EA
100
  }
101
  </style>
102
+ """,
103
+ unsafe_allow_html=True,
104
+ )
105
 
106
  with st.sidebar:
107
  # Add deeploy logo
 
109
  # Ask for model URL and token
110
  host = st.text_input("Host (changing is optional)", "app.deeploy.ml")
111
  model_url, workspace_id, deployment_id = get_model_url()
112
+ deployment_token = st.text_input("Deeploy Model Token", "my-secret-token")
113
  if deployment_token == "my-secret-token":
114
+ # show warning until token has been filled in
115
+ st.warning("Please enter Deeploy API token.")
116
+ else:
117
+ st.button(
118
+ "Get suspicious transaction",
119
+ key="predict_button",
120
+ help="Click to get a suspicious transaction",
121
+ use_container_width=True,
122
+ on_click=disabled,
123
+ disabled=st.session_state.disabled,
124
  )
125
+ ChangeButtonColour("Get suspicious transaction", "#FFFFFF", "#00052D")
 
 
 
 
126
 
127
+ # define client options and instantiate client
128
  client_options = {
129
+ "host": host,
130
+ "deployment_token": deployment_token,
131
+ "workspace_id": workspace_id,
132
  }
133
  client = Client(**client_options)
134
 
135
+ # instantiate session state vars to define whether predict button has been clicked
136
+ # and explanation was retrieved
137
+ if "predict_button" not in st.session_state:
138
  st.session_state.predict_button = False
139
 
140
+ if st.session_state.predict_button:
141
  st.session_state.predict_button_clicked = True
142
 
143
+ if "got_explanation" not in st.session_state:
144
  st.session_state.got_explanation = False
145
 
146
+ # make prediction and explanation calls and store important vars
147
  if st.session_state.predict_button_clicked:
148
  try:
149
  with st.spinner("Loading..."):
 
151
  request_body = get_request_body(datapoint_pd)
152
  # Call the explain endpoint as it also includes the prediction
153
  exp = client.explain(request_body=request_body, deployment_id=deployment_id)
154
+ st.session_state.shap_values = exp["explanations"][0]["shap_values"]
 
 
155
  st.session_state.request_log_id = exp["requestLogId"]
156
  st.session_state.prediction_log_id = exp["predictionLogIds"][0]
157
  st.session_state.datapoint_pd = datapoint_pd
 
167
  + "Contact Deeploy if the problem persists."
168
  )
169
 
170
+ # create warning or info to be shown until prediction has been retrieved
171
  if not st.session_state.got_explanation:
172
+ st.info(
173
  "Fill in left hand side and click on button to observe a potential fraudulent transaction"
174
+ )
175
+
176
+ # store important vars from result of prediction and explanation call
177
  if st.session_state.got_explanation:
178
  shap_values = st.session_state.shap_values
179
  request_log_id = st.session_state.request_log_id
 
182
  certainty = st.session_state.certainty
183
  datapoint = modify_datapoint(datapoint_pd)
184
 
185
+ # create two columns to show data input used and explanation
186
  col1, col2 = st.columns(2)
187
 
188
+ # col1 contains input data table
189
  with col1:
190
  create_data_input_table(datapoint, COL_NAMES)
191
 
192
+ # col 2 contains model certainty and explanation table of top 5 features
193
  with col2:
194
+ st.subheader("AML Model Hit")
195
+ st.metric(label="Model Certainty", value=certainty, delta="threshold: 75%")
196
+ explainability_texts, sorted_indices = get_explainability_texts(
197
+ shap_values, feature_texts
198
+ )
 
 
 
 
199
  weights = get_weights(shap_values, sorted_indices)
200
  explainability_values = get_explainability_values(sorted_indices, datapoint)
201
+ create_table(
202
+ explainability_texts,
203
+ explainability_values,
204
+ weights,
205
+ "Important Suspicious Factors",
206
+ )
207
 
208
  st.subheader("")
 
 
 
 
209
 
210
+ # add var to session state to discern if user has started an evaluation
211
+ if "eval_selected" not in st.session_state:
212
+ st.session_state["eval_selected"] = False
213
 
214
+ # define two columns for agree and disagree button + text area for evaluation input
215
  col3, col4 = st.columns(2)
216
+
217
+ # col 3 contains yes button
218
  with col3:
219
+ # create empty state so that button disappears when st.empty is cleared
220
  eval1 = st.empty()
221
+ eval1.button(
222
+ "Send to FIU",
223
+ key="yes_button",
224
+ use_container_width=True,
225
+ disabled=st.session_state.submitted_disabled,
226
+ )
227
+ ChangeButtonColour("Send to FIU", "#FFFFFF", "#4C506C")
228
  st.session_state.yes_button_clicked = False
229
 
230
  if st.session_state.yes_button:
231
  st.session_state.eval_selected = True
232
+ st.session_state.evaluation_input = {"result": 0} # Agree with the prediction
233
+
234
+ # col 4 contains no button
 
235
  with col4:
236
+ # create empty state so that button disappears when st.empty is cleared
237
  eval2 = st.empty()
238
+ eval2.button(
239
+ "Not money laundering",
240
+ key="no_button",
241
+ use_container_width=True,
242
+ disabled=st.session_state.submitted_disabled,
243
+ )
244
+ ChangeButtonColour("Not money laundering", "#FFFFFF", "#4C506C")
245
  st.session_state.no_button_clicked = False
 
 
246
  if st.session_state.no_button:
247
  st.session_state.no_button_clicked = True
248
  if st.session_state.no_button_clicked:
249
  st.session_state.eval_selected = True
 
250
  st.session_state.evaluation_input = {
251
+ "result": 1, # Disagree with the prediction
252
+ "value": {"predictions": [1]},
253
  }
254
 
255
+ # define process for evaluation
256
  success = False
257
  if st.session_state.eval_selected:
258
+ # if agree button clicked ("Send to FIU"), prefill explanation as comment for evaluation
259
+ # change evaluation is user decides to fill in own text
260
  if st.session_state.yes_button:
261
+ st.session_state.yes_button_clicked = True
262
+ yes_button = True
263
+ explanation = get_comment_explanation(
264
+ certainty, explainability_texts, explainability_values
265
+ )
266
+ st.session_state.yes_button_text = explanation
267
+ comment = st.text_area(
268
+ "Reason for evaluation:",
269
+ st.session_state.yes_button_text,
270
+ key="yes_comment",
271
+ on_change=get_input_yes_button,
272
+ )
273
+ st.session_state.evaluation_input[
274
+ "explanation"
275
+ ] = st.session_state.yes_button_text
276
+
277
+ # if disagree button clicked ("Not money laundering") prefill with text that user
278
+ # has to finish as a reason for evaluation
279
  if st.session_state.no_button:
280
+ comment = st.text_area(
281
+ "Reason for evaluation:",
282
+ st.session_state.no_button_text,
283
+ key="no_comment",
284
+ on_change=get_input_no_button,
285
+ )
286
+ st.session_state.evaluation_input[
287
+ "explanation"
288
+ ] = st.session_state.no_button_text
289
+ # create empty state so that button submit disappears when st.empty is cleared
290
  eval3 = st.empty()
291
+ eval3.button(
292
+ "Submit",
293
+ key="submit_button",
294
+ use_container_width=True,
295
+ on_click=submitted_disabled,
296
+ disabled=st.session_state.submitted_disabled,
297
+ )
298
+ ChangeButtonColour("Submit", "#FFFFFF", "#00052D")
299
+
300
+ # if submit button is clicked, send evaluation to Deeploy
301
  if st.session_state.submit_button:
302
  st.session_state.eval_selected = False
303
+ success = send_evaluation(
304
+ client,
305
+ deployment_id,
306
+ request_log_id,
307
+ prediction_log_id,
308
+ st.session_state.evaluation_input,
309
+ )
310
+ # if the sending of evaluation was successful, remove buttons and enable Next button
311
+ # to be clicked for next prediction and explanation to appear
312
  if success:
313
  st.session_state.eval_selected = False
314
  st.session_state.submitted = True
 
316
  eval2.empty()
317
  eval3.empty()
318
  st.warning("Feedback submitted successfully")
319
+ st.button("Next", key="next", use_container_width=True, on_click=rerun)
320
+ ChangeButtonColour("Next", "#FFFFFF", "#00052D")