|
"""A gradio app for credit card approval prediction using FHE.""" |
|
|
|
import subprocess |
|
import time |
|
import gradio as gr |
|
|
|
from settings import ( |
|
REPO_DIR, |
|
ACCOUNT_MIN_MAX, |
|
CHILDREN_MIN_MAX, |
|
INCOME_MIN_MAX, |
|
AGE_MIN_MAX, |
|
SALARIED_MIN_MAX, |
|
FAMILY_MIN_MAX, |
|
INCOME_TYPES, |
|
OCCUPATION_TYPES, |
|
HOUSING_TYPES, |
|
EDUCATION_TYPES, |
|
FAMILY_STATUS, |
|
) |
|
from backend import ( |
|
keygen_send, |
|
pre_process_encrypt_send_user, |
|
pre_process_encrypt_send_bank, |
|
pre_process_encrypt_send_third_party, |
|
run_fhe, |
|
get_output, |
|
decrypt_output, |
|
) |
|
|
|
|
|
subprocess.Popen(["uvicorn", "server:app"], cwd=REPO_DIR) |
|
time.sleep(3) |
|
|
|
|
|
demo = gr.Blocks() |
|
|
|
|
|
print("Starting the demo...") |
|
with demo: |
|
gr.Markdown( |
|
""" |
|
<h1 align="center">Encrypted Credit Card Approval Prediction Using Fully Homomorphic Encryption</h1> |
|
""" |
|
) |
|
|
|
gr.Markdown("# Client side") |
|
|
|
gr.Markdown("## Step 1: Generate the keys.") |
|
gr.Markdown( |
|
""" |
|
- The private key is used to encrypt and decrypt the data and shall never be shared. |
|
- The evaluation key is a public key that the server needs to process encrypted data. It is |
|
therefore transmitted to the server for further processing as well. |
|
""" |
|
) |
|
keygen_button = gr.Button("Generate the keys and send evaluation key to the server.") |
|
evaluation_key = gr.Textbox( |
|
label="Evaluation key representation:", max_lines=2, interactive=False |
|
) |
|
client_id = gr.Textbox(label="", max_lines=2, interactive=False, visible=False) |
|
|
|
gr.Markdown("## Step 2: Fill in some information.") |
|
gr.Markdown( |
|
""" |
|
Select any information that corresponds to the profile you want to evaluate. Three |
|
dissociated parties are represented : |
|
- the user, which provides some personal information in order to evaluate its credit card |
|
eligibility |
|
- the user's bank, which provides any of the user's banking information relevant to the |
|
decision |
|
- a third party, which represents any other party (here, the user's employer) that could |
|
provide any information relevant to the decision |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.Markdown("### User") |
|
bool_inputs = gr.CheckboxGroup(["Car", "Property", "Work phone", "Phone", "Email"], label="What do you own ?") |
|
num_children = gr.Slider(**CHILDREN_MIN_MAX, step=1, label="Number of children", info="How many children do you have ?") |
|
household_size = gr.Slider(**FAMILY_MIN_MAX, step=1, label="Household size", info="How many members does your household have? ?") |
|
total_income = gr.Slider(**INCOME_MIN_MAX, label="Income", info="What's you total yearly income (in euros) ?") |
|
age = gr.Slider(**AGE_MIN_MAX, step=1, label="Age", info="How old are you ?") |
|
income_type = gr.Dropdown(choices=INCOME_TYPES, value=INCOME_TYPES[0], label="Income type", info="What is your main type of income ?") |
|
education_type = gr.Dropdown(choices=EDUCATION_TYPES, value=EDUCATION_TYPES[0], label="Education", info="What is your education background ?") |
|
family_status = gr.Dropdown(choices=FAMILY_STATUS, value=FAMILY_STATUS[0], label="Family", info="What is your family status ?") |
|
occupation_type = gr.Dropdown(choices=OCCUPATION_TYPES, value=OCCUPATION_TYPES[0], label="Occupation", info="What is your main occupation ?") |
|
housing_type = gr.Dropdown(choices=HOUSING_TYPES, value=HOUSING_TYPES[0], label="Housing", info="In what type of housing do you live ?") |
|
|
|
with gr.Column(): |
|
gr.Markdown("### Bank ") |
|
account_age = gr.Slider(**ACCOUNT_MIN_MAX, step=1, label="Account age (months)", info="How long have this person had this bank account (in months) ?") |
|
|
|
with gr.Column(): |
|
gr.Markdown("### Third party ") |
|
salaried = gr.Radio(["Yes", "No"], label="Is the person salaried ?", value="Yes") |
|
years_salaried = gr.Slider(**SALARIED_MIN_MAX, step=1, label="Years of employment", info="How long have this person been salaried (in years) ?") |
|
|
|
|
|
gr.Markdown("## Step 3: Encrypt the inputs using FHE and send them to the server.") |
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.Markdown("### User") |
|
encrypt_button_user = gr.Button("Encrypt the inputs and send to server.") |
|
|
|
encrypted_input_user = gr.Textbox( |
|
label="Encrypted input representation:", max_lines=2, interactive=False |
|
) |
|
|
|
|
|
with gr.Column(): |
|
gr.Markdown("### Bank ") |
|
encrypt_button_bank = gr.Button("Encrypt the inputs and send to server.") |
|
|
|
encrypted_input_bank = gr.Textbox( |
|
label="Encrypted input representation:", max_lines=2, interactive=False |
|
) |
|
|
|
|
|
with gr.Column(): |
|
gr.Markdown("### Third Party ") |
|
encrypt_button_third_party = gr.Button("Encrypt the inputs and send to server.") |
|
|
|
encrypted_input_third_party = gr.Textbox( |
|
label="Encrypted input representation:", max_lines=2, interactive=False |
|
) |
|
|
|
gr.Markdown("# Server side") |
|
gr.Markdown( |
|
""" |
|
Once the server receives the encrypted inputs, it can compute the prediction without ever |
|
needing to decrypt any value. |
|
|
|
This server employs an [XGBoost](https://github.com/dmlc/xgboost) classifier model that has |
|
been trained on [this credit card data-set](https://www.kaggle.com/datasets/rikdifos/credit-card-approval-prediction/data). |
|
""" |
|
) |
|
|
|
gr.Markdown("## Step 4: Run FHE execution.") |
|
execute_fhe_button = gr.Button("Run FHE execution.") |
|
fhe_execution_time = gr.Textbox( |
|
label="Total FHE execution time (in seconds):", max_lines=1, interactive=False |
|
) |
|
|
|
gr.Markdown("# Client side") |
|
gr.Markdown( |
|
""" |
|
Once the server completed the inference, the encrypted output is returned to the user. |
|
""" |
|
) |
|
|
|
gr.Markdown("## Step 5: Receive the encrypted output from the server.") |
|
gr.Markdown( |
|
""" |
|
The value displayed below is a shortened byte representation of the actual encrypted output. |
|
""" |
|
) |
|
|
|
get_output_button = gr.Button("Receive the encrypted output from the server.") |
|
encrypted_output_representation = gr.Textbox( |
|
label="Encrypted output representation: ", max_lines=2, interactive=False |
|
) |
|
|
|
gr.Markdown("## Step 6: Decrypt the output.") |
|
gr.Markdown( |
|
""" |
|
The user is able to decrypt the prediction using its private key. |
|
""" |
|
) |
|
|
|
decrypt_button = gr.Button("Decrypt the output") |
|
prediction_output = gr.Textbox( |
|
label="Prediction", max_lines=1, interactive=False |
|
) |
|
|
|
|
|
keygen_button.click( |
|
keygen_send, |
|
outputs=[client_id, evaluation_key, keygen_button], |
|
) |
|
|
|
|
|
|
|
encrypt_button_user.click( |
|
pre_process_encrypt_send_user, |
|
inputs=[client_id, bool_inputs, num_children, household_size, total_income, age, \ |
|
income_type, education_type, family_status, occupation_type, housing_type], |
|
outputs=[encrypted_input_user], |
|
) |
|
|
|
|
|
|
|
encrypt_button_bank.click( |
|
pre_process_encrypt_send_bank, |
|
inputs=[client_id, account_age], |
|
outputs=[encrypted_input_bank], |
|
) |
|
|
|
|
|
|
|
encrypt_button_third_party.click( |
|
pre_process_encrypt_send_third_party, |
|
inputs=[client_id, salaried, years_salaried], |
|
outputs=[encrypted_input_third_party], |
|
) |
|
|
|
|
|
execute_fhe_button.click(run_fhe, inputs=[client_id], outputs=[fhe_execution_time]) |
|
|
|
|
|
get_output_button.click( |
|
get_output, |
|
inputs=[client_id], |
|
outputs=[encrypted_output_representation], |
|
) |
|
|
|
|
|
decrypt_button.click( |
|
decrypt_output, |
|
inputs=[client_id], |
|
outputs=[prediction_output], |
|
) |
|
|
|
gr.Markdown( |
|
"The app was built with [Concrete-ML](https://github.com/zama-ai/concrete-ml), a " |
|
"Privacy-Preserving Machine Learning (PPML) open-source set of tools by [Zama](https://zama.ai/). " |
|
"Try it yourself and don't forget to star on Github ⭐." |
|
) |
|
|
|
demo.launch(share=False) |
|
|