| import streamlit as st |
| import pandas as pd |
| import logging |
| from deeploy import Client, CreateEvaluation |
| from utils import ( |
| get_request_body, |
| get_fake_certainty, |
| get_model_url, |
| get_random_suspicious_transaction, |
| ) |
| from utils import ( |
| get_explainability_texts, |
| get_explainability_values, |
| send_evaluation, |
| get_comment_explanation, |
| ) |
| from utils import COL_NAMES, feature_texts |
| from utils import ( |
| create_data_input_table, |
| create_table, |
| ChangeButtonColour, |
| get_weights, |
| modify_datapoint, |
| ) |
|
|
| logging.basicConfig(level=logging.INFO) |
|
|
| st.set_page_config(layout="wide") |
|
|
| st.title("Smart AML:tm:") |
| st.divider() |
|
|
| |
| data = pd.read_pickle("data/preprocessed_data.pkl") |
|
|
| |
| if "predict_button_clicked" not in st.session_state: |
| st.session_state.predict_button_clicked = False |
|
|
| if "submitted_disabled" not in st.session_state: |
| st.session_state.submitted_disabled = False |
|
|
| if "disabled" not in st.session_state: |
| st.session_state.disabled = False |
|
|
| if "no_button_text" not in st.session_state: |
| st.session_state.no_button_text = ( |
| "I don't think this transaction is money laundering because..." |
| ) |
|
|
| if "yes_button_text" not in st.session_state: |
| st.session_state.yes_button_text = "" |
|
|
| if "yes_button_clicked" not in st.session_state: |
| st.session_state.yes_button_clicked = False |
|
|
|
|
| |
| |
| def get_input_no_button(): |
| st.session_state.no_button_text = comment.replace( |
| st.session_state.no_button_text, st.session_state.no_comment |
| ) |
| st.session_state.evaluation_input["comment"] = st.session_state.no_button_text |
|
|
|
|
| |
| def get_input_yes_button(): |
| st.session_state.yes_button_text = comment.replace( |
| st.session_state.yes_button_text, st.session_state.yes_comment |
| ) |
| st.session_state.evaluation_input["comment"] = st.session_state.yes_button_text |
|
|
|
|
| |
| def disabled(): |
| st.session_state.disabled = True |
|
|
|
|
| |
| def rerun(): |
| st.session_state.predict_button_clicked = True |
| st.session_state.submitted_disabled = False |
| st.session_state.no_button_text = ( |
| "I don't think this transaction is money laundering because..." |
| ) |
|
|
|
|
| |
| def submitted_disabled(): |
| st.session_state.submitted_disabled = True |
|
|
|
|
| |
| st.markdown( |
| """ |
| <style> |
| [data-testid=stSidebar] { |
| background-color: #E0E0E0; ##E5E6EA |
| } |
| </style> |
| """, |
| unsafe_allow_html=True, |
| ) |
|
|
| with st.sidebar: |
| |
| st.image("deeploy_logo.png", width=270) |
| |
| host = st.text_input("Host (changing is optional)", "app.deeploy.ml") |
| model_url, workspace_id, deployment_id = get_model_url() |
| deployment_token = st.text_input("Deeploy API token", "my-secret-token") |
| if deployment_token == "my-secret-token": |
| |
| st.warning("Please enter Deeploy API token.") |
| else: |
| 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, |
| ) |
| ChangeButtonColour("Get suspicious transaction", "#FFFFFF", "#00052D") |
|
|
| |
| client_options = { |
| "host": host, |
| "deployment_token": deployment_token, |
| "workspace_id": workspace_id, |
| } |
| client = Client(**client_options) |
|
|
| |
| |
| if "predict_button" not in st.session_state: |
| st.session_state.predict_button = False |
|
|
| if st.session_state.predict_button: |
| st.session_state.predict_button_clicked = True |
|
|
| if "got_explanation" not in st.session_state: |
| st.session_state.got_explanation = False |
|
|
| |
| if st.session_state.predict_button_clicked: |
| try: |
| with st.spinner("Loading..."): |
| datapoint_pd = get_random_suspicious_transaction(data) |
| request_body = get_request_body(datapoint_pd) |
| |
| exp = client.explain(request_body=request_body, deployment_id=deployment_id) |
| st.session_state.shap_values = exp["explanations"][0]["shap_values"] |
| st.session_state.request_log_id = exp["requestLogId"] |
| st.session_state.prediction_log_id = exp["predictionLogIds"][0] |
| st.session_state.datapoint_pd = datapoint_pd |
| certainty = get_fake_certainty() |
| st.session_state.certainty = certainty |
| st.session_state.got_explanation = True |
| st.session_state.predict_button_clicked = False |
| except Exception as e: |
| logging.error(e) |
| st.error( |
| "Failed to retrieve the prediction or explanation." |
| + "Check whether you are using the right model URL and Token. " |
| + "Contact Deeploy if the problem persists." |
| ) |
|
|
| |
| if not st.session_state.got_explanation: |
| st.info( |
| "Fill in left hand side and click on button to observe a potential fraudulent transaction" |
| ) |
|
|
| |
| if st.session_state.got_explanation: |
| shap_values = st.session_state.shap_values |
| request_log_id = st.session_state.request_log_id |
| prediction_log_id = st.session_state.prediction_log_id |
| datapoint_pd = st.session_state.datapoint_pd |
| certainty = st.session_state.certainty |
| datapoint = modify_datapoint(datapoint_pd) |
|
|
| |
| col1, col2 = st.columns(2) |
|
|
| |
| with col1: |
| create_data_input_table(datapoint, COL_NAMES) |
|
|
| |
| with col2: |
| st.subheader("AML Model Hit") |
| st.metric(label="Model Certainty", value=certainty, delta="threshold: 75%") |
| explainability_texts, sorted_indices = get_explainability_texts( |
| shap_values, feature_texts |
| ) |
| weights = get_weights(shap_values, sorted_indices) |
| explainability_values = get_explainability_values(sorted_indices, datapoint) |
| create_table( |
| explainability_texts, |
| explainability_values, |
| weights, |
| "Important Suspicious Factors", |
| ) |
|
|
| st.subheader("") |
|
|
| |
| if "eval_selected" not in st.session_state: |
| st.session_state["eval_selected"] = False |
|
|
| |
| col3, col4 = st.columns(2) |
|
|
| |
| with col3: |
| |
| eval1 = st.empty() |
| eval1.button( |
| "Send to FIU", |
| key="yes_button", |
| use_container_width=True, |
| disabled=st.session_state.submitted_disabled, |
| ) |
| ChangeButtonColour("Send to FIU", "#FFFFFF", "#4C506C") |
| st.session_state.yes_button_clicked = False |
|
|
| if st.session_state.yes_button: |
| st.session_state.eval_selected = True |
| st.session_state.evaluation_input = {"agree": True} |
|
|
| |
| with col4: |
| |
| eval2 = st.empty() |
| eval2.button( |
| "Not money laundering", |
| key="no_button", |
| use_container_width=True, |
| disabled=st.session_state.submitted_disabled, |
| ) |
| ChangeButtonColour("Not money laundering", "#FFFFFF", "#4C506C") |
| st.session_state.no_button_clicked = False |
| if st.session_state.no_button: |
| st.session_state.no_button_clicked = True |
| if st.session_state.no_button_clicked: |
| st.session_state.eval_selected = True |
| st.session_state.evaluation_input = { |
| "agree": False, |
| "desired_output": {"predictions": [1]}, |
| } |
|
|
| |
| success = False |
| if st.session_state.eval_selected: |
| |
| |
| if st.session_state.yes_button: |
| st.session_state.yes_button_clicked = True |
| yes_button = True |
| explanation = get_comment_explanation( |
| certainty, explainability_texts, explainability_values |
| ) |
| st.session_state.yes_button_text = explanation |
| comment = st.text_area( |
| "Reason for evaluation:", |
| st.session_state.yes_button_text, |
| key="yes_comment", |
| on_change=get_input_yes_button, |
| ) |
| st.session_state.evaluation_input[ |
| "comment" |
| ] = st.session_state.yes_button_text |
|
|
| |
| |
| if st.session_state.no_button: |
| comment = st.text_area( |
| "Reason for evaluation:", |
| st.session_state.no_button_text, |
| key="no_comment", |
| on_change=get_input_no_button, |
| ) |
| st.session_state.evaluation_input[ |
| "comment" |
| ] = st.session_state.no_button_text |
| |
| eval3 = st.empty() |
| eval3.button( |
| "Submit", |
| key="submit_button", |
| use_container_width=True, |
| on_click=submitted_disabled, |
| disabled=st.session_state.submitted_disabled, |
| ) |
| ChangeButtonColour("Submit", "#FFFFFF", "#00052D") |
|
|
| |
| if st.session_state.submit_button: |
| st.session_state.eval_selected = False |
| success = send_evaluation( |
| client, |
| deployment_id, |
| request_log_id, |
| prediction_log_id, |
| st.session_state.evaluation_input, |
| ) |
| |
| |
| if success: |
| st.session_state.eval_selected = False |
| st.session_state.submitted = True |
| eval1.empty() |
| eval2.empty() |
| eval3.empty() |
| st.success("Feedback submitted successfully") |
| st.button("Next", key="next", use_container_width=True, on_click=rerun) |
| ChangeButtonColour("Next", "#FFFFFF", "#00052D") |
|
|