Commit
Β·
03475de
1
Parent(s):
59a3f3b
Add checkmarks to all buttons
Browse files- app.py +26 -21
- backend.py +9 -6
app.py
CHANGED
|
@@ -40,6 +40,24 @@ demo = gr.Blocks()
|
|
| 40 |
|
| 41 |
print("Starting the demo...")
|
| 42 |
with demo:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
with gr.Accordion("What is credit scoring for card approval?", open=False):
|
| 44 |
gr.Markdown(
|
| 45 |
"""
|
|
@@ -100,19 +118,6 @@ with demo:
|
|
| 100 |
|
| 101 |
gr.Markdown(
|
| 102 |
"""
|
| 103 |
-
<p align="center">
|
| 104 |
-
<img width=200 src="file/images/logos/zama.jpg">
|
| 105 |
-
</p>
|
| 106 |
-
<h1 align="center">Encrypted Credit Card Approval Prediction Using Fully Homomorphic Encryption</h1>
|
| 107 |
-
<p align="center">
|
| 108 |
-
<a href="https://github.com/zama-ai/concrete-ml"> <img style="vertical-align: middle; display:inline-block; margin-right: 3px;" width=15 src="file/images/logos/github.png">Concrete-ML</a>
|
| 109 |
-
β
|
| 110 |
-
<a href="https://docs.zama.ai/concrete-ml"> <img style="vertical-align: middle; display:inline-block; margin-right: 3px;" width=15 src="file/images/logos/documentation.png">Documentation</a>
|
| 111 |
-
β
|
| 112 |
-
<a href="https://zama.ai/community"> <img style="vertical-align: middle; display:inline-block; margin-right: 3px;" width=15 src="file/images/logos/community.png">Community</a>
|
| 113 |
-
β
|
| 114 |
-
<a href="https://twitter.com/zama_fhe"> <img style="vertical-align: middle; display:inline-block; margin-right: 3px;" width=15 src="file/images/logos/x.png">@zama_fhe</a>
|
| 115 |
-
</p>
|
| 116 |
<p align="center">
|
| 117 |
<img src="file/images/banner.png">
|
| 118 |
</p>
|
|
@@ -278,7 +283,7 @@ with demo:
|
|
| 278 |
pre_process_encrypt_send_applicant,
|
| 279 |
inputs=[client_id, bool_inputs, num_children, household_size, total_income, age, \
|
| 280 |
income_type, education_type, family_status, occupation_type, housing_type],
|
| 281 |
-
outputs=[encrypted_input_applicant],
|
| 282 |
)
|
| 283 |
|
| 284 |
# Button to pre-process, generate the key, encrypt and send the bank inputs from the client
|
|
@@ -286,7 +291,7 @@ with demo:
|
|
| 286 |
encrypt_button_bank.click(
|
| 287 |
pre_process_encrypt_send_bank,
|
| 288 |
inputs=[client_id, account_age],
|
| 289 |
-
outputs=[encrypted_input_bank],
|
| 290 |
)
|
| 291 |
|
| 292 |
# Button to pre-process, generate the key, encrypt and send the credit bureau inputs from the
|
|
@@ -294,10 +299,10 @@ with demo:
|
|
| 294 |
encrypt_button_credit_bureau.click(
|
| 295 |
pre_process_encrypt_send_credit_bureau,
|
| 296 |
inputs=[client_id, years_employed, employed],
|
| 297 |
-
outputs=[encrypted_input_credit_bureau],
|
| 298 |
)
|
| 299 |
|
| 300 |
-
gr.Markdown("## Step 3: Run FHE
|
| 301 |
gr.Markdown("<hr />")
|
| 302 |
gr.Markdown("<span style='color:grey'>Server Side</span>")
|
| 303 |
gr.Markdown(
|
|
@@ -310,13 +315,13 @@ with demo:
|
|
| 310 |
"""
|
| 311 |
)
|
| 312 |
|
| 313 |
-
execute_fhe_button = gr.Button("Run FHE
|
| 314 |
fhe_execution_time = gr.Textbox(
|
| 315 |
label="Total FHE execution time (in seconds):", max_lines=1, interactive=False
|
| 316 |
)
|
| 317 |
|
| 318 |
# Button to send the encodings to the server using post method
|
| 319 |
-
execute_fhe_button.click(run_fhe, inputs=[client_id], outputs=[fhe_execution_time])
|
| 320 |
|
| 321 |
gr.Markdown("## Step 4: Receive the encrypted output from the server and decrypt.")
|
| 322 |
gr.Markdown("<hr />")
|
|
@@ -350,7 +355,7 @@ with demo:
|
|
| 350 |
get_output_button.click(
|
| 351 |
get_output_and_decrypt,
|
| 352 |
inputs=[client_id],
|
| 353 |
-
outputs=[prediction_output, encrypted_output_representation],
|
| 354 |
)
|
| 355 |
|
| 356 |
gr.Markdown("## Step 5 (optional): Explain the prediction.")
|
|
@@ -380,7 +385,7 @@ with demo:
|
|
| 380 |
explain_button.click(
|
| 381 |
explain_encrypt_run_decrypt,
|
| 382 |
inputs=[client_id, prediction_output, years_employed, employed],
|
| 383 |
-
outputs=[explain_prediction],
|
| 384 |
)
|
| 385 |
|
| 386 |
gr.Markdown(
|
|
|
|
| 40 |
|
| 41 |
print("Starting the demo...")
|
| 42 |
with demo:
|
| 43 |
+
gr.Markdown(
|
| 44 |
+
"""
|
| 45 |
+
<p align="center">
|
| 46 |
+
<img width=200 src="file/images/logos/zama.jpg">
|
| 47 |
+
</p>
|
| 48 |
+
<h1 align="center">Encrypted Credit Card Approval Prediction Using Fully Homomorphic Encryption</h1>
|
| 49 |
+
<p align="center">
|
| 50 |
+
<a href="https://github.com/zama-ai/concrete-ml"> <img style="vertical-align: middle; display:inline-block; margin-right: 3px;" width=15 src="file/images/logos/github.png">Concrete-ML</a>
|
| 51 |
+
β
|
| 52 |
+
<a href="https://docs.zama.ai/concrete-ml"> <img style="vertical-align: middle; display:inline-block; margin-right: 3px;" width=15 src="file/images/logos/documentation.png">Documentation</a>
|
| 53 |
+
β
|
| 54 |
+
<a href="https://zama.ai/community"> <img style="vertical-align: middle; display:inline-block; margin-right: 3px;" width=15 src="file/images/logos/community.png">Community</a>
|
| 55 |
+
β
|
| 56 |
+
<a href="https://twitter.com/zama_fhe"> <img style="vertical-align: middle; display:inline-block; margin-right: 3px;" width=15 src="file/images/logos/x.png">@zama_fhe</a>
|
| 57 |
+
</p>
|
| 58 |
+
"""
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
with gr.Accordion("What is credit scoring for card approval?", open=False):
|
| 62 |
gr.Markdown(
|
| 63 |
"""
|
|
|
|
| 118 |
|
| 119 |
gr.Markdown(
|
| 120 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
<p align="center">
|
| 122 |
<img src="file/images/banner.png">
|
| 123 |
</p>
|
|
|
|
| 283 |
pre_process_encrypt_send_applicant,
|
| 284 |
inputs=[client_id, bool_inputs, num_children, household_size, total_income, age, \
|
| 285 |
income_type, education_type, family_status, occupation_type, housing_type],
|
| 286 |
+
outputs=[encrypted_input_applicant, encrypt_button_applicant],
|
| 287 |
)
|
| 288 |
|
| 289 |
# Button to pre-process, generate the key, encrypt and send the bank inputs from the client
|
|
|
|
| 291 |
encrypt_button_bank.click(
|
| 292 |
pre_process_encrypt_send_bank,
|
| 293 |
inputs=[client_id, account_age],
|
| 294 |
+
outputs=[encrypted_input_bank, encrypt_button_bank],
|
| 295 |
)
|
| 296 |
|
| 297 |
# Button to pre-process, generate the key, encrypt and send the credit bureau inputs from the
|
|
|
|
| 299 |
encrypt_button_credit_bureau.click(
|
| 300 |
pre_process_encrypt_send_credit_bureau,
|
| 301 |
inputs=[client_id, years_employed, employed],
|
| 302 |
+
outputs=[encrypted_input_credit_bureau, encrypt_button_credit_bureau],
|
| 303 |
)
|
| 304 |
|
| 305 |
+
gr.Markdown("## Step 3: Run the FHE evaluation.")
|
| 306 |
gr.Markdown("<hr />")
|
| 307 |
gr.Markdown("<span style='color:grey'>Server Side</span>")
|
| 308 |
gr.Markdown(
|
|
|
|
| 315 |
"""
|
| 316 |
)
|
| 317 |
|
| 318 |
+
execute_fhe_button = gr.Button("Run the FHE evaluation.")
|
| 319 |
fhe_execution_time = gr.Textbox(
|
| 320 |
label="Total FHE execution time (in seconds):", max_lines=1, interactive=False
|
| 321 |
)
|
| 322 |
|
| 323 |
# Button to send the encodings to the server using post method
|
| 324 |
+
execute_fhe_button.click(run_fhe, inputs=[client_id], outputs=[fhe_execution_time, execute_fhe_button])
|
| 325 |
|
| 326 |
gr.Markdown("## Step 4: Receive the encrypted output from the server and decrypt.")
|
| 327 |
gr.Markdown("<hr />")
|
|
|
|
| 355 |
get_output_button.click(
|
| 356 |
get_output_and_decrypt,
|
| 357 |
inputs=[client_id],
|
| 358 |
+
outputs=[prediction_output, encrypted_output_representation, get_output_button],
|
| 359 |
)
|
| 360 |
|
| 361 |
gr.Markdown("## Step 5 (optional): Explain the prediction.")
|
|
|
|
| 385 |
explain_button.click(
|
| 386 |
explain_encrypt_run_decrypt,
|
| 387 |
inputs=[client_id, prediction_output, years_employed, employed],
|
| 388 |
+
outputs=[explain_prediction, explain_button],
|
| 389 |
)
|
| 390 |
|
| 391 |
gr.Markdown(
|
backend.py
CHANGED
|
@@ -242,7 +242,7 @@ def _encrypt_send(client_id, inputs, client_type):
|
|
| 242 |
|
| 243 |
_send_to_server(client_id, client_type, file_name)
|
| 244 |
|
| 245 |
-
return encrypted_inputs_short
|
| 246 |
|
| 247 |
|
| 248 |
def pre_process_encrypt_send_applicant(client_id, *inputs):
|
|
@@ -355,7 +355,7 @@ def run_fhe(client_id):
|
|
| 355 |
data=data,
|
| 356 |
) as response:
|
| 357 |
if response.ok:
|
| 358 |
-
return response.json()
|
| 359 |
else:
|
| 360 |
raise gr.Error("Please send the inputs from all three parties to the server first.")
|
| 361 |
|
|
@@ -402,6 +402,7 @@ def get_output_and_decrypt(client_id):
|
|
| 402 |
return (
|
| 403 |
APPROVED_MESSAGE if output == 1 else DENIED_MESSAGE,
|
| 404 |
encrypted_output_short,
|
|
|
|
| 405 |
)
|
| 406 |
|
| 407 |
else:
|
|
@@ -426,6 +427,8 @@ def explain_encrypt_run_decrypt(client_id, prediction_output, *inputs):
|
|
| 426 |
raise gr.Error(
|
| 427 |
"Explaining the prediction can only be done if the credit card is likely to be denied."
|
| 428 |
)
|
|
|
|
|
|
|
| 429 |
|
| 430 |
# Retrieve the credit bureau inputs
|
| 431 |
years_employed, employed = inputs
|
|
@@ -458,14 +461,14 @@ def explain_encrypt_run_decrypt(client_id, prediction_output, *inputs):
|
|
| 458 |
# likely tried the bin suggested in a previous explainability run. In that case, we
|
| 459 |
# confirm that the credit card is likely to be approved
|
| 460 |
if years_employed_bin == years_employed:
|
| 461 |
-
return APPROVED_MESSAGE
|
| 462 |
|
| 463 |
# Else, that means the applicant is looking for some explainability. We therefore
|
| 464 |
# suggest to try the obtained bin
|
| 465 |
return (
|
| 466 |
DENIED_MESSAGE + f" However, having at least {years_employed_bin} years of "
|
| 467 |
"employment would increase your chance of having your credit card approved."
|
| 468 |
-
)
|
| 469 |
|
| 470 |
# In case no bins made the model predict an approval, explain why
|
| 471 |
return (
|
|
@@ -473,12 +476,12 @@ def explain_encrypt_run_decrypt(client_id, prediction_output, *inputs):
|
|
| 473 |
f"{YEARS_EMPLOYED_BINS[-1]} years does not seem to be enough to get an approval based "
|
| 474 |
"on the given inputs. Other inputs like the income or the account's age might have "
|
| 475 |
"bigger impact in this particular case."
|
| 476 |
-
)
|
| 477 |
|
| 478 |
# In case the applicant tried the "oldest" bin (but still got denied), explain why
|
| 479 |
return (
|
| 480 |
DENIED_MESSAGE + " Unfortunately, you already have the maximum amount of years of "
|
| 481 |
f"employment ({years_employed} years). Other inputs like the income or the account's age "
|
| 482 |
"might have a bigger impact in this particular case."
|
| 483 |
-
)
|
| 484 |
|
|
|
|
| 242 |
|
| 243 |
_send_to_server(client_id, client_type, file_name)
|
| 244 |
|
| 245 |
+
return encrypted_inputs_short, gr.update(value="Inputs are encrypted and sent to server. β
")
|
| 246 |
|
| 247 |
|
| 248 |
def pre_process_encrypt_send_applicant(client_id, *inputs):
|
|
|
|
| 355 |
data=data,
|
| 356 |
) as response:
|
| 357 |
if response.ok:
|
| 358 |
+
return response.json(), gr.update(value="FHE evaluation is done. β
")
|
| 359 |
else:
|
| 360 |
raise gr.Error("Please send the inputs from all three parties to the server first.")
|
| 361 |
|
|
|
|
| 402 |
return (
|
| 403 |
APPROVED_MESSAGE if output == 1 else DENIED_MESSAGE,
|
| 404 |
encrypted_output_short,
|
| 405 |
+
gr.update(value="Encrypted outputs have been received from the server. β
"),
|
| 406 |
)
|
| 407 |
|
| 408 |
else:
|
|
|
|
| 427 |
raise gr.Error(
|
| 428 |
"Explaining the prediction can only be done if the credit card is likely to be denied."
|
| 429 |
)
|
| 430 |
+
|
| 431 |
+
button_update = gr.update(value="Prediction has been explained. β
")
|
| 432 |
|
| 433 |
# Retrieve the credit bureau inputs
|
| 434 |
years_employed, employed = inputs
|
|
|
|
| 461 |
# likely tried the bin suggested in a previous explainability run. In that case, we
|
| 462 |
# confirm that the credit card is likely to be approved
|
| 463 |
if years_employed_bin == years_employed:
|
| 464 |
+
return APPROVED_MESSAGE, button_update
|
| 465 |
|
| 466 |
# Else, that means the applicant is looking for some explainability. We therefore
|
| 467 |
# suggest to try the obtained bin
|
| 468 |
return (
|
| 469 |
DENIED_MESSAGE + f" However, having at least {years_employed_bin} years of "
|
| 470 |
"employment would increase your chance of having your credit card approved."
|
| 471 |
+
), button_update
|
| 472 |
|
| 473 |
# In case no bins made the model predict an approval, explain why
|
| 474 |
return (
|
|
|
|
| 476 |
f"{YEARS_EMPLOYED_BINS[-1]} years does not seem to be enough to get an approval based "
|
| 477 |
"on the given inputs. Other inputs like the income or the account's age might have "
|
| 478 |
"bigger impact in this particular case."
|
| 479 |
+
), button_update
|
| 480 |
|
| 481 |
# In case the applicant tried the "oldest" bin (but still got denied), explain why
|
| 482 |
return (
|
| 483 |
DENIED_MESSAGE + " Unfortunately, you already have the maximum amount of years of "
|
| 484 |
f"employment ({years_employed} years). Other inputs like the income or the account's age "
|
| 485 |
"might have a bigger impact in this particular case."
|
| 486 |
+
), button_update
|
| 487 |
|