romanbredehoft-zama
commited on
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 |
|