romanbredehoft-zama commited on
Commit
8d5cb63
1 Parent(s): bc345ce

Refactor send files to server

Browse files
Files changed (4) hide show
  1. app.py +11 -11
  2. backend.py +24 -44
  3. server.py +10 -23
  4. settings.py +1 -1
app.py CHANGED
@@ -10,7 +10,7 @@ from settings import (
10
  CHILDREN_MIN_MAX,
11
  INCOME_MIN_MAX,
12
  AGE_MIN_MAX,
13
- EMPLOYED_MIN_MAX,
14
  FAMILY_MIN_MAX,
15
  INCOME_TYPES,
16
  OCCUPATION_TYPES,
@@ -40,7 +40,7 @@ print("Starting the demo...")
40
  with demo:
41
  gr.Markdown(
42
  """
43
- <h1 align="center">Credit Card Approval Prediction Using Fully Homomorphic Encryption</h1>
44
  """
45
  )
46
 
@@ -57,10 +57,10 @@ with demo:
57
  gr.Markdown("### User")
58
  gender = gr.Radio(["Female", "Male"], label="Gender", value="Female")
59
  bool_inputs = gr.CheckboxGroup(["Car", "Property", "Work phone", "Phone", "Email"], label="What do you own ?")
60
- num_children = gr.Slider(**CHILDREN_MIN_MAX, step=1, label="Number of children", info="How many children do you have (0 to 19) ?")
61
- num_family = gr.Slider(**FAMILY_MIN_MAX, step=1, label="Family", info="How many members does your family have? (1 to 20) ?")
62
- total_income = gr.Slider(**INCOME_MIN_MAX, label="Income", info="What's you total yearly income (in euros, 3780 to 220500) ?")
63
- age = gr.Slider(**AGE_MIN_MAX, step=1, label="Age", info="How old are you (20 to 68) ?")
64
  income_type = gr.Dropdown(choices=INCOME_TYPES, value=INCOME_TYPES[0], label="Income type", info="What is your main type of income ?")
65
  education_type = gr.Dropdown(choices=EDUCATION_TYPES, value=EDUCATION_TYPES[0], label="Education", info="What is your education background ?")
66
  family_status = gr.Dropdown(choices=FAMILY_STATUS, value=FAMILY_STATUS[0], label="Family", info="What is your family status ?")
@@ -69,12 +69,12 @@ with demo:
69
 
70
  with gr.Column():
71
  gr.Markdown("### Bank ")
72
- account_length = gr.Slider(**ACCOUNT_MIN_MAX, step=1, label="Account length", info="How long have this person had this account (in months, 0 to 60) ?")
73
 
74
  with gr.Column():
75
  gr.Markdown("### Third party ")
76
- employed = gr.Radio(["Yes", "No"], label="Is the person employed ?", value="Yes")
77
- years_employed = gr.Slider(**EMPLOYED_MIN_MAX, step=1, label="Years of employment", info="How long have this person been employed (in years, 0 to 43) ?")
78
 
79
 
80
  gr.Markdown("### Step 3: Encrypt using FHE and send the inputs to the server.")
@@ -153,7 +153,7 @@ with demo:
153
  # side to the server
154
  encrypt_button_user.click(
155
  pre_process_encrypt_send_user,
156
- inputs=[client_id, gender, bool_inputs, num_children, num_family, total_income, age, \
157
  income_type, education_type, family_status, occupation_type, housing_type],
158
  outputs=[encrypted_input_user],
159
  )
@@ -170,7 +170,7 @@ with demo:
170
  # client side to the server
171
  encrypt_button_third_party.click(
172
  pre_process_encrypt_send_third_party,
173
- inputs=[client_id, employed, years_employed],
174
  outputs=[encrypted_input_third_party],
175
  )
176
 
 
10
  CHILDREN_MIN_MAX,
11
  INCOME_MIN_MAX,
12
  AGE_MIN_MAX,
13
+ SALARIED_MIN_MAX,
14
  FAMILY_MIN_MAX,
15
  INCOME_TYPES,
16
  OCCUPATION_TYPES,
 
40
  with demo:
41
  gr.Markdown(
42
  """
43
+ <h1 align="center">Encrypted Credit Card Approval Prediction Using Fully Homomorphic Encryption</h1>
44
  """
45
  )
46
 
 
57
  gr.Markdown("### User")
58
  gender = gr.Radio(["Female", "Male"], label="Gender", value="Female")
59
  bool_inputs = gr.CheckboxGroup(["Car", "Property", "Work phone", "Phone", "Email"], label="What do you own ?")
60
+ num_children = gr.Slider(**CHILDREN_MIN_MAX, step=1, label="Number of children", info="How many children do you have ?")
61
+ household_size = gr.Slider(**FAMILY_MIN_MAX, step=1, label="Household size", info="How many members does your family have? ?")
62
+ total_income = gr.Slider(**INCOME_MIN_MAX, label="Income", info="What's you total yearly income (in euros) ?")
63
+ age = gr.Slider(**AGE_MIN_MAX, step=1, label="Age", info="How old are you ?")
64
  income_type = gr.Dropdown(choices=INCOME_TYPES, value=INCOME_TYPES[0], label="Income type", info="What is your main type of income ?")
65
  education_type = gr.Dropdown(choices=EDUCATION_TYPES, value=EDUCATION_TYPES[0], label="Education", info="What is your education background ?")
66
  family_status = gr.Dropdown(choices=FAMILY_STATUS, value=FAMILY_STATUS[0], label="Family", info="What is your family status ?")
 
69
 
70
  with gr.Column():
71
  gr.Markdown("### Bank ")
72
+ account_length = gr.Slider(**ACCOUNT_MIN_MAX, step=1, label="Account length", info="How long have this person had this account (in months) ?")
73
 
74
  with gr.Column():
75
  gr.Markdown("### Third party ")
76
+ salaried = gr.Radio(["Yes", "No"], label="Is the person salaried ?", value="Yes")
77
+ years_salaried = gr.Slider(**SALARIED_MIN_MAX, step=1, label="Years of employment", info="How long have this person been salaried (in years) ?")
78
 
79
 
80
  gr.Markdown("### Step 3: Encrypt using FHE and send the inputs to the server.")
 
153
  # side to the server
154
  encrypt_button_user.click(
155
  pre_process_encrypt_send_user,
156
+ inputs=[client_id, gender, bool_inputs, num_children, household_size, total_income, age, \
157
  income_type, education_type, family_status, occupation_type, housing_type],
158
  outputs=[encrypted_input_user],
159
  )
 
170
  # client side to the server
171
  encrypt_button_third_party.click(
172
  pre_process_encrypt_send_third_party,
173
+ inputs=[client_id, salaried, years_salaried],
174
  outputs=[encrypted_input_third_party],
175
  )
176
 
backend.py CHANGED
@@ -103,7 +103,7 @@ def _get_client_file_path(name, client_id, client_type=None):
103
  """Get the file path for the client.
104
 
105
  Args:
106
- name (str): The desired file name (either 'evaluation_key', 'encrypted_inputs') of
107
  'encrypted_outputs').
108
  client_id (int): The client ID to consider.
109
  client_type (Optional[str]): The type of user to consider (either 'user', 'bank',
@@ -122,33 +122,6 @@ def _get_client_file_path(name, client_id, client_type=None):
122
  return dir_path / f"{name}{client_type_suffix}"
123
 
124
 
125
- def _send_eval_key(client_id, evaluation_key_path):
126
- """Send the evaluation key to the server.
127
-
128
- Args:
129
- client_id (int): The client ID to consider.
130
- evaluation_key_path (Path): Path to the evaluation key to send.
131
- """
132
-
133
- # Define the data and files to post
134
- data = {
135
- "client_id": client_id,
136
- }
137
-
138
- files = [
139
- ("files", open(evaluation_key_path, "rb")),
140
- ]
141
-
142
- # Send the evaluation key to the server
143
- url = SERVER_URL + "send_eval_key"
144
- with requests.post(
145
- url=url,
146
- data=data,
147
- files=files,
148
- ) as response:
149
- return response.ok
150
-
151
-
152
  def keygen_send():
153
  """Generate the private and evaluation key, and send the evaluation key to the server.
154
 
@@ -170,41 +143,46 @@ def keygen_send():
170
  # Retrieve the serialized evaluation key
171
  evaluation_key = client.get_serialized_evaluation_keys()
172
 
 
 
173
  # Save evaluation key as bytes in a file as it is too large to pass through regular Gradio
174
  # buttons (see https://github.com/gradio-app/gradio/issues/1877)
175
- evaluation_key_path = _get_client_file_path("evaluation_key", client_id)
176
 
177
  with evaluation_key_path.open("wb") as evaluation_key_file:
178
  evaluation_key_file.write(evaluation_key)
179
 
180
  # Send the evaluation key to the server
181
- _send_eval_key(client_id, evaluation_key_path)
182
 
183
  return client_id, gr.update(value="Keys are generated and sent ✅")
184
 
185
 
186
- def _send_input(client_id, client_type):
187
- """Send the encrypted inputs as well as the evaluation key to the server.
188
 
189
  Args:
190
  client_id (int): The client ID to consider.
191
- client_type (str): The type of client to consider (either 'user', 'bank' or 'third_party').
 
 
192
  """
193
  # Get the paths to the encrypted inputs
194
- encrypted_input_path = _get_client_file_path("encrypted_inputs", client_id, client_type)
195
 
196
  # Define the data and files to post
197
  data = {
198
  "client_id": client_id,
199
  "client_type": client_type,
 
200
  }
201
 
202
  files = [
203
- ("files", open(encrypted_input_path, "rb")),
204
  ]
205
 
206
- # Send the encrypted inputs and evaluation key to the server
207
- url = SERVER_URL + "send_input"
208
  with requests.post(
209
  url=url,
210
  data=data,
@@ -237,9 +215,11 @@ def _encrypt_send(client_id, inputs, client_type):
237
  input_slice=INPUT_SLICES[client_type],
238
  )
239
 
 
 
240
  # Save encrypted_inputs to bytes in a file, since too large to pass through regular Gradio
241
  # buttons, https://github.com/gradio-app/gradio/issues/1877
242
- encrypted_inputs_path = _get_client_file_path("encrypted_inputs", client_id, client_type)
243
 
244
  with encrypted_inputs_path.open("wb") as encrypted_inputs_file:
245
  encrypted_inputs_file.write(encrypted_inputs)
@@ -247,7 +227,7 @@ def _encrypt_send(client_id, inputs, client_type):
247
  # Create a truncated version of the encrypted inputs for display
248
  encrypted_inputs_short = shorten_bytes_object(encrypted_inputs)
249
 
250
- _send_input(client_id, client_type)
251
 
252
  return encrypted_inputs_short
253
 
@@ -263,7 +243,7 @@ def pre_process_encrypt_send_user(client_id, *inputs):
263
  (int, bytes): Integer ID representing the current client and a byte short representation of
264
  the encrypted input to send.
265
  """
266
- gender, bool_inputs, num_children, num_family, total_income, age, income_type, education_type, \
267
  family_status, occupation_type, housing_type = inputs
268
 
269
  # Encoding given in https://www.kaggle.com/code/samuelcortinhas/credit-cards-data-cleaning
@@ -285,7 +265,7 @@ def pre_process_encrypt_send_user(client_id, *inputs):
285
  "Phone": [phone],
286
  "Email": [email],
287
  "Num_children": num_children,
288
- "Num_family": num_family,
289
  "Total_income": total_income,
290
  "Age": age,
291
  "Income_type": income_type,
@@ -327,14 +307,14 @@ def pre_process_encrypt_send_third_party(client_id, *inputs):
327
  (int, bytes): Integer ID representing the current client and a byte short representation of
328
  the encrypted input to send.
329
  """
330
- employed, years_employed = inputs
331
 
332
  # Original dataset contains an "unemployed" feature instead of "employed"
333
- unemployed = employed == "No"
334
 
335
  third_party_inputs = pandas.DataFrame({
336
  "Unemployed": [unemployed],
337
- "Years_employed": [years_employed],
338
  })
339
 
340
  preprocessed_third_party_inputs = PRE_PROCESSOR_THIRD_PARTY.transform(third_party_inputs)
 
103
  """Get the file path for the client.
104
 
105
  Args:
106
+ name (str): The desired file name (either 'evaluation_key', 'encrypted_inputs' or
107
  'encrypted_outputs').
108
  client_id (int): The client ID to consider.
109
  client_type (Optional[str]): The type of user to consider (either 'user', 'bank',
 
122
  return dir_path / f"{name}{client_type_suffix}"
123
 
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  def keygen_send():
126
  """Generate the private and evaluation key, and send the evaluation key to the server.
127
 
 
143
  # Retrieve the serialized evaluation key
144
  evaluation_key = client.get_serialized_evaluation_keys()
145
 
146
+ file_name = "evaluation_key"
147
+
148
  # Save evaluation key as bytes in a file as it is too large to pass through regular Gradio
149
  # buttons (see https://github.com/gradio-app/gradio/issues/1877)
150
+ evaluation_key_path = _get_client_file_path(file_name, client_id)
151
 
152
  with evaluation_key_path.open("wb") as evaluation_key_file:
153
  evaluation_key_file.write(evaluation_key)
154
 
155
  # Send the evaluation key to the server
156
+ _send_to_server(client_id, None, file_name)
157
 
158
  return client_id, gr.update(value="Keys are generated and sent ✅")
159
 
160
 
161
+ def _send_to_server(client_id, client_type, file_name):
162
+ """Send the encrypted inputs or the evaluation key to the server.
163
 
164
  Args:
165
  client_id (int): The client ID to consider.
166
+ client_type (Optional[str]): The type of client to consider (either 'user', 'bank', 'third_party' or
167
+ None).
168
+ file_name (str): File name to send (either 'evaluation_key' or 'encrypted_inputs').
169
  """
170
  # Get the paths to the encrypted inputs
171
+ encrypted_file_path = _get_client_file_path(file_name, client_id, client_type)
172
 
173
  # Define the data and files to post
174
  data = {
175
  "client_id": client_id,
176
  "client_type": client_type,
177
+ "file_name": file_name,
178
  }
179
 
180
  files = [
181
+ ("files", open(encrypted_file_path, "rb")),
182
  ]
183
 
184
+ # Send the encrypted inputs or evaluation key to the server
185
+ url = SERVER_URL + "send_file"
186
  with requests.post(
187
  url=url,
188
  data=data,
 
215
  input_slice=INPUT_SLICES[client_type],
216
  )
217
 
218
+ file_name = "encrypted_inputs"
219
+
220
  # Save encrypted_inputs to bytes in a file, since too large to pass through regular Gradio
221
  # buttons, https://github.com/gradio-app/gradio/issues/1877
222
+ encrypted_inputs_path = _get_client_file_path(file_name, client_id, client_type)
223
 
224
  with encrypted_inputs_path.open("wb") as encrypted_inputs_file:
225
  encrypted_inputs_file.write(encrypted_inputs)
 
227
  # Create a truncated version of the encrypted inputs for display
228
  encrypted_inputs_short = shorten_bytes_object(encrypted_inputs)
229
 
230
+ _send_to_server(client_id, client_type, file_name)
231
 
232
  return encrypted_inputs_short
233
 
 
243
  (int, bytes): Integer ID representing the current client and a byte short representation of
244
  the encrypted input to send.
245
  """
246
+ gender, bool_inputs, num_children, household_size, total_income, age, income_type, education_type, \
247
  family_status, occupation_type, housing_type = inputs
248
 
249
  # Encoding given in https://www.kaggle.com/code/samuelcortinhas/credit-cards-data-cleaning
 
265
  "Phone": [phone],
266
  "Email": [email],
267
  "Num_children": num_children,
268
+ "Num_family": household_size,
269
  "Total_income": total_income,
270
  "Age": age,
271
  "Income_type": income_type,
 
307
  (int, bytes): Integer ID representing the current client and a byte short representation of
308
  the encrypted input to send.
309
  """
310
+ salaried, years_salaried = inputs
311
 
312
  # Original dataset contains an "unemployed" feature instead of "employed"
313
+ unemployed = salaried == "No"
314
 
315
  third_party_inputs = pandas.DataFrame({
316
  "Unemployed": [unemployed],
317
+ "Years_employed": [years_salaried],
318
  })
319
 
320
  preprocessed_third_party_inputs = PRE_PROCESSOR_THIRD_PARTY.transform(third_party_inputs)
server.py CHANGED
@@ -1,7 +1,7 @@
1
  """Server that will listen for GET and POST requests from the client."""
2
 
3
  import time
4
- from typing import List
5
  from fastapi import FastAPI, File, Form, UploadFile
6
  from fastapi.responses import JSONResponse, Response
7
 
@@ -44,33 +44,20 @@ def root():
44
  return {"message": "Welcome to Credit Card Approval Prediction server!"}
45
 
46
 
47
- @app.post("/send_eval_key")
48
- def send_eval_key(
49
  client_id: str = Form(),
 
 
50
  files: List[UploadFile] = File(),
51
  ):
52
- """Send the evaluation key to the server."""
53
- # Retrieve the evaluation key path
54
- evaluation_key_path = _get_server_file_path("evaluation_key", client_id)
55
-
56
- # Write the file using the above path
57
- with evaluation_key_path.open("wb") as evaluation_key:
58
- evaluation_key.write(files[0].file.read())
59
-
60
-
61
- @app.post("/send_input")
62
- def send_input(
63
- client_id: str = Form(),
64
- client_type: str = Form(),
65
- files: List[UploadFile] = File(),
66
- ):
67
- """Send the inputs to the server."""
68
- # Retrieve the encrypted inputs
69
- encrypted_inputs_path = _get_server_file_path("encrypted_inputs", client_id, client_type)
70
 
71
  # Write the file using the above path
72
- with encrypted_inputs_path.open("wb") as encrypted_inputs:
73
- encrypted_inputs.write(files[0].file.read())
74
 
75
 
76
  @app.post("/run_fhe")
 
1
  """Server that will listen for GET and POST requests from the client."""
2
 
3
  import time
4
+ from typing import List, Optional
5
  from fastapi import FastAPI, File, Form, UploadFile
6
  from fastapi.responses import JSONResponse, Response
7
 
 
44
  return {"message": "Welcome to Credit Card Approval Prediction server!"}
45
 
46
 
47
+ @app.post("/send_file")
48
+ def send_file(
49
  client_id: str = Form(),
50
+ client_type: Optional[str] = Form(None),
51
+ file_name: str = Form(),
52
  files: List[UploadFile] = File(),
53
  ):
54
+ """Send the files to the server."""
55
+ # Retrieve the encrypted inputs or evaluation key
56
+ encrypted_file_path = _get_server_file_path(file_name, client_id, client_type)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
  # Write the file using the above path
59
+ with encrypted_file_path.open("wb") as encrypted_file:
60
+ encrypted_file.write(files[0].file.read())
61
 
62
 
63
  @app.post("/run_fhe")
settings.py CHANGED
@@ -60,7 +60,7 @@ ACCOUNT_MIN_MAX = get_min_max(_data, "Account_length")
60
  CHILDREN_MIN_MAX = get_min_max(_data, "Num_children")
61
  INCOME_MIN_MAX = get_min_max(_data, "Total_income")
62
  AGE_MIN_MAX = get_min_max(_data, "Age")
63
- EMPLOYED_MIN_MAX = get_min_max(_data, "Years_employed")
64
  FAMILY_MIN_MAX = get_min_max(_data, "Num_family")
65
 
66
  # App data choices
 
60
  CHILDREN_MIN_MAX = get_min_max(_data, "Num_children")
61
  INCOME_MIN_MAX = get_min_max(_data, "Total_income")
62
  AGE_MIN_MAX = get_min_max(_data, "Age")
63
+ SALARIED_MIN_MAX = get_min_max(_data, "Years_employed")
64
  FAMILY_MIN_MAX = get_min_max(_data, "Num_family")
65
 
66
  # App data choices