working version
Browse files- app.py +131 -89
- utils.py +7 -0
- visual_components.py +14 -9
app.py
CHANGED
@@ -3,7 +3,7 @@ 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
|
7 |
from utils import COL_NAMES, feature_texts
|
8 |
from visual_components import create_data_input_table, create_table, ChangeButtonColour
|
9 |
|
@@ -15,16 +15,30 @@ st.title("Money Laundering System")
|
|
15 |
st.divider()
|
16 |
|
17 |
data = pd.read_pickle("data/preprocessed_data.pkl")
|
18 |
-
# data = data.drop('isFraud', axis=1)
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
|
|
|
|
|
|
23 |
|
24 |
-
# Initialize disabled for form_submit_button to False
|
25 |
if "disabled" not in st.session_state:
|
26 |
st.session_state.disabled = False
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
st.markdown("""
|
29 |
<style>
|
30 |
[data-testid=stSidebar] {
|
@@ -39,16 +53,16 @@ with st.sidebar:
|
|
39 |
# Ask for model URL and token
|
40 |
host = st.text_input("Host (changing is optional)", "app.deeploy.ml")
|
41 |
model_url, workspace_id, deployment_id = get_model_url()
|
42 |
-
deployment_token = st.text_input("Deeploy Model Token", "my-secret-token
|
43 |
if deployment_token == "my-secret-token":
|
44 |
st.warning(
|
45 |
"Please enter Deeploy API token."
|
46 |
)
|
47 |
-
else:
|
48 |
-
st.button("Get suspicious transaction", key="predict_button", help="Click to get a suspicious transaction", use_container_width=True, on_click=
|
49 |
) #on_click=lambda: st.experimental_rerun()
|
50 |
ChangeButtonColour("Get suspicious transaction", '#FFFFFF', "#00052D")#'#FFFFFF', "#00052D"
|
51 |
-
|
52 |
|
53 |
# define client optsions and instantiate client
|
54 |
client_options = {
|
@@ -58,82 +72,31 @@ with st.sidebar:
|
|
58 |
}
|
59 |
client = Client(**client_options)
|
60 |
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
-
if
|
65 |
-
st.session_state.predict_button = False
|
66 |
-
st.info(
|
67 |
-
"Fill in left hand side and click on button to observe a potential fraudulent transaction"
|
68 |
-
)
|
69 |
-
if st.session_state.predict_button:
|
70 |
try:
|
71 |
with st.spinner("Loading..."):
|
72 |
datapoint_pd = get_random_suspicious_transaction(data)
|
73 |
request_body = get_request_body(datapoint_pd)
|
74 |
-
|
75 |
exp = client.explain(request_body=request_body, deployment_id=deployment_id)
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
create_data_input_table(datapoint_pd, COL_NAMES)
|
84 |
-
with col2:
|
85 |
-
st.subheader('Prediction Explanation: ')
|
86 |
certainty = get_fake_certainty()
|
87 |
-
st.
|
88 |
-
|
89 |
-
|
90 |
-
explainability_values = get_explainability_values(sorted_indices, datapoint_pd)
|
91 |
-
create_table(explainability_texts, explainability_values, 'Important Suspicious Variables: ')
|
92 |
-
|
93 |
-
st.subheader("")
|
94 |
-
# st.markdown("<h2 style='text-align: center; white: red;'>Evaluation</h2>", unsafe_allow_html=True)
|
95 |
-
|
96 |
-
col3, col4 = st.columns(2)
|
97 |
-
|
98 |
-
with col3:
|
99 |
-
st.button("Send to FIU", key="yes_button", use_container_width=True)
|
100 |
-
ChangeButtonColour("Send to FIU", '#FFFFFF', "#DD360C")
|
101 |
-
if 'eval_selected' not in st.session_state:
|
102 |
-
st.session_state['eval_selected'] = False
|
103 |
-
# if yes_button:
|
104 |
-
# st.session_state.eval_selected = True
|
105 |
-
# st.session_state.evaluation_input = {
|
106 |
-
# "result": 0 # Agree with the prediction
|
107 |
-
# }
|
108 |
-
|
109 |
-
with col4:
|
110 |
-
st.button("Not money laundering", key="no_button", use_container_width=True)
|
111 |
-
ChangeButtonColour("Not money laundering", '#FFFFFF', "#46B071")
|
112 |
-
# if no_button:
|
113 |
-
# st.session_state.eval_selected = True
|
114 |
-
# desired_output = not predictions[0]
|
115 |
-
# st.session_state.evaluation_input = {
|
116 |
-
# "result": 1, # Disagree with the prediction
|
117 |
-
# "value": {"predictions": [desired_output]},
|
118 |
-
# }
|
119 |
-
|
120 |
-
success = False
|
121 |
-
if st.session_state.eval_selected:
|
122 |
-
comment = st.text_input("Would you like to add a comment?")
|
123 |
-
if comment:
|
124 |
-
st.session_state.evaluation_input["explanation"] = comment
|
125 |
-
logging.debug("Selected feedback:" + str(st.session_state.evaluation_input))
|
126 |
-
if st.button("Submit", key="submit_button"):
|
127 |
-
st.session_state.eval_selected = False
|
128 |
-
# success = send_evaluation(client, deployment_id, request_log_id, prediction_log_id, st.session_state.evaluation_input)
|
129 |
-
if success:
|
130 |
-
st.session_state.eval_selected = False
|
131 |
-
st.success("Feedback submitted successfully.")
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
except Exception as e:
|
138 |
logging.error(e)
|
139 |
st.error(
|
@@ -142,14 +105,93 @@ if st.session_state.predict_button:
|
|
142 |
+ "Contact Deeploy if the problem persists."
|
143 |
)
|
144 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
st.session_state
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_explanation
|
7 |
from utils import COL_NAMES, feature_texts
|
8 |
from visual_components import create_data_input_table, create_table, ChangeButtonColour
|
9 |
|
|
|
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.predict_button_clicked = True
|
31 |
+
st.session_state.disabled = True
|
32 |
+
|
33 |
+
def rerun():
|
34 |
+
st.session_state.predict_button_clicked = True
|
35 |
+
st.session_state.submitted_disabled = False
|
36 |
+
|
37 |
+
|
38 |
+
def submitted_disabled():
|
39 |
+
st.session_state.submitted_disabled = True
|
40 |
+
|
41 |
+
|
42 |
st.markdown("""
|
43 |
<style>
|
44 |
[data-testid=stSidebar] {
|
|
|
53 |
# Ask for model URL and token
|
54 |
host = st.text_input("Host (changing is optional)", "app.deeploy.ml")
|
55 |
model_url, workspace_id, deployment_id = get_model_url()
|
56 |
+
deployment_token = st.text_input("Deeploy Model Token", "DPTjVXffSvkAATY1KEeNRGghUEd0iugjYBGKTLTIjtZa3aheZcF1esLBP4F6mYhvk48hF8vy8uZmC8MzwUVFwE7JIPeNCSEjxTCqHOjzsGzNW0ydFA4W") # my-secret-token
|
57 |
if deployment_token == "my-secret-token":
|
58 |
st.warning(
|
59 |
"Please enter Deeploy API token."
|
60 |
)
|
61 |
+
else:
|
62 |
+
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
|
63 |
) #on_click=lambda: st.experimental_rerun()
|
64 |
ChangeButtonColour("Get suspicious transaction", '#FFFFFF', "#00052D")#'#FFFFFF', "#00052D"
|
65 |
+
|
66 |
|
67 |
# define client optsions and instantiate client
|
68 |
client_options = {
|
|
|
72 |
}
|
73 |
client = Client(**client_options)
|
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 'explanation' not in st.session_state:
|
79 |
+
# st.session_state.explanation = ""
|
80 |
+
if 'got_explanation' not in st.session_state:
|
81 |
+
st.session_state.got_explanation = False
|
82 |
|
83 |
+
if st.session_state.predict_button_clicked:
|
|
|
|
|
|
|
|
|
|
|
84 |
try:
|
85 |
with st.spinner("Loading..."):
|
86 |
datapoint_pd = get_random_suspicious_transaction(data)
|
87 |
request_body = get_request_body(datapoint_pd)
|
88 |
+
# Call the explain endpoint as it also includes the prediction
|
89 |
exp = client.explain(request_body=request_body, deployment_id=deployment_id)
|
90 |
+
# request_log_id = exp["requestLogId"]
|
91 |
+
# prediction_log_id = exp["predictionLogIds"][0]
|
92 |
+
st.session_state.shap_values = exp['explanations'][0]['shap_values']
|
93 |
+
st.session_state.request_log_id = exp["requestLogId"]
|
94 |
+
st.session_state.prediction_log_id = exp["predictionLogIds"][0]
|
95 |
+
st.session_state.datapoint_pd = datapoint_pd
|
|
|
|
|
|
|
|
|
96 |
certainty = get_fake_certainty()
|
97 |
+
st.session_state.certainty = certainty
|
98 |
+
st.session_state.got_explanation = True
|
99 |
+
st.session_state.predict_button_clicked = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
except Exception as e:
|
101 |
logging.error(e)
|
102 |
st.error(
|
|
|
105 |
+ "Contact Deeploy if the problem persists."
|
106 |
)
|
107 |
|
108 |
+
if not st.session_state.got_explanation:
|
109 |
+
st.info(
|
110 |
+
"Fill in left hand side and click on button to observe a potential fraudulent transaction"
|
111 |
+
)
|
112 |
+
if st.session_state.got_explanation:
|
113 |
+
shap_values = st.session_state.shap_values
|
114 |
+
request_log_id = st.session_state.request_log_id
|
115 |
+
prediction_log_id = st.session_state.prediction_log_id
|
116 |
+
datapoint_pd = st.session_state.datapoint_pd
|
117 |
+
certainty = st.session_state.certainty
|
118 |
+
|
119 |
+
col1, col2 = st.columns(2)
|
120 |
+
|
121 |
+
with col1:
|
122 |
+
create_data_input_table(datapoint_pd, COL_NAMES)
|
123 |
+
|
124 |
+
with col2:
|
125 |
+
st.subheader('Prediction Explanation: ')
|
126 |
+
# st.metric(label='#### Model Certainty', value=certainty)
|
127 |
+
st.markdown('#### Model Certainty')
|
128 |
+
st.success(f'{certainty}')
|
129 |
+
|
130 |
+
explainability_texts, sorted_indices = get_explainability_texts(shap_values, feature_texts)
|
131 |
+
explainability_values = get_explainability_values(sorted_indices, datapoint_pd)
|
132 |
+
create_table(explainability_texts, explainability_values, 'Important Suspicious Variables: ')
|
133 |
+
|
134 |
+
st.subheader("")
|
135 |
+
# st.markdown("<h2 style='text-align: center; white: red;'>Evaluation</h2>", unsafe_allow_html=True)
|
136 |
+
|
137 |
+
if 'eval_selected' not in st.session_state:
|
138 |
+
st.session_state['eval_selected'] = False
|
139 |
+
|
140 |
+
|
141 |
+
col3, col4 = st.columns(2)
|
142 |
+
with col3:
|
143 |
+
eval1 = st.empty()
|
144 |
+
eval1.button("Send to FIU", key="yes_button", use_container_width=True, disabled=st.session_state.submitted_disabled)
|
145 |
+
ChangeButtonColour("Send to FIU", '#FFFFFF', "#DD360C")
|
146 |
+
st.session_state.yes_button_clicked = False
|
147 |
+
|
148 |
+
if st.session_state.yes_button:
|
149 |
+
st.session_state.eval_selected = True
|
150 |
+
st.session_state.evaluation_input = {
|
151 |
+
"result": 0 # Agree with the prediction
|
152 |
+
}
|
153 |
+
|
154 |
+
with col4:
|
155 |
+
eval2 = st.empty()
|
156 |
+
eval2.button("Not money laundering", key="no_button", use_container_width=True, disabled=st.session_state.submitted_disabled)
|
157 |
+
ChangeButtonColour("Not money laundering", '#FFFFFF', "#46B071")
|
158 |
+
st.session_state.no_button_clicked = False
|
159 |
+
|
160 |
+
|
161 |
+
if st.session_state.no_button:
|
162 |
+
st.session_state.no_button_clicked = True
|
163 |
+
if st.session_state.no_button_clicked:
|
164 |
+
st.session_state.eval_selected = True
|
165 |
+
desired_output = 1
|
166 |
+
st.session_state.evaluation_input = {
|
167 |
+
"result": 1, # Disagree with the prediction
|
168 |
+
"value": {"predictions": [desired_output]},
|
169 |
+
}
|
170 |
|
171 |
+
success = False
|
172 |
+
if st.session_state.eval_selected:
|
173 |
+
# st.write('after eval')
|
174 |
+
# st.write(st.session_state)
|
175 |
+
if st.session_state.yes_button:
|
176 |
+
explanation = get_explanation(certainty, explainability_texts, explainability_values)
|
177 |
+
comment = st.text_area("Reason for evaluation:", explanation)
|
178 |
+
st.session_state.evaluation_input["explanation"] = comment
|
179 |
+
if st.session_state.no_button:
|
180 |
+
comment = st.text_area("Reason for evaluation:", "I don't think this transaction is money laundering because...")
|
181 |
+
st.session_state.evaluation_input["explanation"] = comment
|
182 |
+
logging.debug("Selected feedback:" + str(st.session_state.evaluation_input))
|
183 |
+
eval3 = st.empty()
|
184 |
+
eval3.button("Submit", key="submit_button", use_container_width=True, on_click=submitted_disabled, disabled=st.session_state.submitted_disabled)
|
185 |
+
ChangeButtonColour("Submit", '#FFFFFF', "#00052D")
|
186 |
+
if st.session_state.submit_button:
|
187 |
+
st.session_state.eval_selected = False
|
188 |
+
success = send_evaluation(client, deployment_id, request_log_id, prediction_log_id, st.session_state.evaluation_input)
|
189 |
+
if success:
|
190 |
+
st.session_state.eval_selected = False
|
191 |
+
st.session_state.submitted = True
|
192 |
+
eval1.empty()
|
193 |
+
eval2.empty()
|
194 |
+
eval3.empty()
|
195 |
+
st.success("Feedback submitted successfully.")
|
196 |
+
st.button("Next", key='next', use_container_width=True, on_click=rerun)
|
197 |
+
ChangeButtonColour("Next", '#FFFFFF', "#F9B917")
|
utils.py
CHANGED
@@ -120,3 +120,10 @@ def get_model_url():
|
|
120 |
deployment_id = ""
|
121 |
return model_url, workspace_id, deployment_id
|
122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
deployment_id = ""
|
121 |
return model_url, workspace_id, deployment_id
|
122 |
|
123 |
+
def get_explanation(certainty, explainability_texts, explainability_values):
|
124 |
+
cleaned = [x.replace(':', '') for x in explainability_texts]
|
125 |
+
fi = [f'{explainability_texts[i]} is {x}' for i,x in enumerate(cleaned)]
|
126 |
+
fi.insert(0, 'Important suspicious features: ')
|
127 |
+
result = '\n'.join(fi)
|
128 |
+
comment = f"Model certainty is {certainty}" + '\n''\n' + result
|
129 |
+
return comment
|
visual_components.py
CHANGED
@@ -24,22 +24,27 @@ def create_table(texts, values, title):
|
|
24 |
# df = df.style.set_properties(**{
|
25 |
# 'selector': 'th',
|
26 |
# 'props': [
|
27 |
-
# ('background-color', 'black')
|
28 |
# ('color', 'cyan')]
|
29 |
# })
|
30 |
# df = df.style.set_properties(**{'background-color': 'black',
|
31 |
# 'color': 'green'})
|
32 |
|
33 |
st.markdown(f'#### {title}') # Markdown for styling
|
34 |
-
headers = {
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
38 |
|
39 |
-
df = df.style.set_table_styles({
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
43 |
|
44 |
# df.style.set_table_styles([headers])
|
45 |
st.dataframe(df, hide_index=True, width=450) # Display a simple table
|
|
|
24 |
# df = df.style.set_properties(**{
|
25 |
# 'selector': 'th',
|
26 |
# 'props': [
|
27 |
+
# ('background-color', 'black'),``
|
28 |
# ('color', 'cyan')]
|
29 |
# })
|
30 |
# df = df.style.set_properties(**{'background-color': 'black',
|
31 |
# 'color': 'green'})
|
32 |
|
33 |
st.markdown(f'#### {title}') # Markdown for styling
|
34 |
+
# headers = {
|
35 |
+
# 'selector': 'th',
|
36 |
+
# 'props': 'background-color' '#67c5a4'#'background-color: #000066; color: white;'
|
37 |
+
# }
|
38 |
+
header = {
|
39 |
+
'selector': 'th',
|
40 |
+
'props': 'background-color: #000066; color: white;'
|
41 |
+
}
|
42 |
|
43 |
+
# df = df.style.set_table_styles({
|
44 |
+
# ('Feature Explanation', 'Value'): [{'selector': 'th', 'props': 'border-left: 1px solid white'},
|
45 |
+
# {'selector': 'td', 'props': 'border-left: 1px solid #000066'}]
|
46 |
+
# }, axis=0)
|
47 |
+
df = df.style.set_table_styles([header])
|
48 |
|
49 |
# df.style.set_table_styles([headers])
|
50 |
st.dataframe(df, hide_index=True, width=450) # Display a simple table
|