80cols commited on
Commit
3176588
Β·
verified Β·
1 Parent(s): 33da34d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +334 -334
app.py CHANGED
@@ -85,433 +85,433 @@ print(f"{MAPPING_DOC_EMBEDDING.keys()=}")
85
  USER_ID = numpy.random.randint(0, 2**32)
86
 
87
 
88
- def select_static_anonymized_sentences_fn(selected_sentences: List):
89
 
90
- selected_sentences = [MAPPING_ANONYMIZED_SENTENCES[sentence] for sentence in selected_sentences]
91
 
92
- anonymized_selected_sentence = sorted(selected_sentences, key=lambda x: x[0])
93
 
94
- anonymized_selected_sentence = [sentence for _, sentence in anonymized_selected_sentence]
95
 
96
- return "\n\n".join(anonymized_selected_sentence)
97
 
98
 
99
- def key_gen_fn() -> Dict:
100
- """Generate keys for a given user."""
101
 
102
- print("------------ Step 1: Key Generation:")
103
 
104
- print(f"Your user ID is: {USER_ID}....")
105
 
106
 
107
- client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{USER_ID}")
108
- client.load()
109
 
110
- # Creates the private and evaluation keys on the client side
111
- client.generate_private_and_evaluation_keys()
112
 
113
- # Get the serialized evaluation keys
114
- serialized_evaluation_keys = client.get_serialized_evaluation_keys()
115
- assert isinstance(serialized_evaluation_keys, bytes)
116
 
117
- # Save the evaluation key
118
- evaluation_key_path = KEYS_DIR / f"{USER_ID}/evaluation_key"
119
 
120
- write_bytes(evaluation_key_path, serialized_evaluation_keys)
121
 
122
- # anonymizer.generate_key()
123
 
124
- if not evaluation_key_path.is_file():
125
- error_message = (
126
- f"Error Encountered While generating the evaluation {evaluation_key_path.is_file()=}"
127
- )
128
- print(error_message)
129
- return {gen_key_btn: gr.update(value=error_message)}
130
- else:
131
- print("Keys have been generated βœ…")
132
- return {gen_key_btn: gr.update(value="Keys have been generated βœ…")}
133
 
134
 
135
- def encrypt_doc_fn(doc):
136
 
137
- print(f"\n------------ Step 2.1: Doc encryption: {doc=}")
138
 
139
- if not (KEYS_DIR / f"{USER_ID}/evaluation_key").is_file():
140
- return {encrypted_doc_box: gr.update(value="Error ❌: Please generate the key first!", lines=10)}
141
 
142
- # Retrieve the client API
143
- client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{USER_ID}")
144
- client.load()
145
 
146
- encrypted_tokens = []
147
- tokens = re.findall(r"(\b[\w\.\/\-@]+\b|[\s,.!?;:'\"-]+|\$\d+(?:\.\d+)?|\€\d+(?:\.\d+)?)", ' '.join(doc))
148
 
149
- for token in tokens:
150
- if token.strip() and re.match(r"\w+", token):
151
- emb_x = MAPPING_DOC_EMBEDDING[token]
152
- assert emb_x.shape == (1, 1024)
153
- encrypted_x = client.quantize_encrypt_serialize(emb_x)
154
- assert isinstance(encrypted_x, bytes)
155
- encrypted_tokens.append(encrypted_x)
156
 
157
- print("Doc encrypted βœ… on Client Side")
158
 
159
- # No need to save it
160
- # write_bytes(KEYS_DIR / f"{USER_ID}/encrypted_doc", b"".join(encrypted_tokens))
161
 
162
- encrypted_quant_tokens_hex = [token.hex()[500:510] for token in encrypted_tokens]
163
 
164
- return {
165
- encrypted_doc_box: gr.update(value=" ".join(encrypted_quant_tokens_hex), lines=10),
166
- anonymized_doc_output: gr.update(visible=True, value=None),
167
- }
168
 
169
 
170
- def encrypt_query_fn(query):
171
 
172
- print(f"\n------------ Step 2: Query encryption: {query=}")
173
 
174
- if not (KEYS_DIR / f"{USER_ID}/evaluation_key").is_file():
175
- return {output_encrypted_box: gr.update(value="Error ❌: Please generate the key first!", lines=8)}
176
 
177
- if is_user_query_valid(query):
178
- return {
179
- query_box: gr.update(
180
- value=(
181
- "Unable to process ❌: The request exceeds the length limit or falls "
182
- "outside the scope of this document. Please refine your query."
183
- )
184
- )
185
- }
186
 
187
- # Retrieve the client API
188
- client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{USER_ID}")
189
- client.load()
190
 
191
- encrypted_tokens = []
192
 
193
- # Pattern to identify words and non-words (including punctuation, spaces, etc.)
194
- tokens = re.findall(r"(\b[\w\.\/\-@]+\b|[\s,.!?;:'\"-]+)", query)
195
 
196
- for token in tokens:
197
 
198
- # 1- Ignore non-words tokens
199
- if bool(re.match(r"^\s+$", token)):
200
- continue
201
 
202
- # 2- Directly append non-word tokens or whitespace to processed_tokens
203
 
204
- # Prediction for each word
205
- emb_x = get_batch_text_representation([token], EMBEDDINGS_MODEL, TOKENIZER)
206
- encrypted_x = client.quantize_encrypt_serialize(emb_x)
207
- assert isinstance(encrypted_x, bytes)
208
 
209
- encrypted_tokens.append(encrypted_x)
210
 
211
- print("Data encrypted βœ… on Client Side")
212
 
213
- assert len({len(token) for token in encrypted_tokens}) == 1
214
 
215
- write_bytes(KEYS_DIR / f"{USER_ID}/encrypted_input", b"".join(encrypted_tokens))
216
- write_bytes(
217
- KEYS_DIR / f"{USER_ID}/encrypted_input_len", len(encrypted_tokens[0]).to_bytes(10, "big")
218
- )
219
 
220
- encrypted_quant_tokens_hex = [token.hex()[500:580] for token in encrypted_tokens]
221
 
222
- return {
223
- output_encrypted_box: gr.update(value=" ".join(encrypted_quant_tokens_hex), lines=8),
224
- anonymized_query_output: gr.update(visible=True, value=None),
225
- identified_words_output_df: gr.update(visible=False, value=None),
226
- }
227
 
228
 
229
- def send_input_fn(query) -> Dict:
230
- """Send the encrypted data and the evaluation key to the server."""
231
 
232
- print("------------ Step 3.1: Send encrypted_data to the Server")
233
 
234
- evaluation_key_path = KEYS_DIR / f"{USER_ID}/evaluation_key"
235
- encrypted_input_path = KEYS_DIR / f"{USER_ID}/encrypted_input"
236
- encrypted_input_len_path = KEYS_DIR / f"{USER_ID}/encrypted_input_len"
237
 
238
- if not evaluation_key_path.is_file():
239
- error_message = (
240
- "Error Encountered While Sending Data to the Server: "
241
- f"The key has been generated correctly - {evaluation_key_path.is_file()=}"
242
- )
243
- return {anonymized_query_output: gr.update(value=error_message)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
 
245
- if not encrypted_input_path.is_file():
246
- error_message = (
247
- "Error Encountered While Sending Data to the Server: The data has not been encrypted "
248
- f"correctly on the client side - {encrypted_input_path.is_file()=}"
249
- )
250
- return {anonymized_query_output: gr.update(value=error_message)}
251
 
252
- # Define the data and files to post
253
- data = {"user_id": USER_ID, "input": query}
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
- files = [
256
- ("files", open(evaluation_key_path, "rb")),
257
- ("files", open(encrypted_input_path, "rb")),
258
- ("files", open(encrypted_input_len_path, "rb")),
259
- ]
 
 
 
 
 
260
 
261
- # Send the encrypted input and evaluation key to the server
262
- url = SERVER_URL + "send_input"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
 
264
- with requests.post(
265
- url=url,
266
- data=data,
267
- files=files,
268
- ) as resp:
269
- print("Data sent to the server βœ…" if resp.ok else "Error ❌ in sending data to the server")
270
 
 
 
271
 
272
- def run_fhe_in_server_fn() -> Dict:
273
- """Run in FHE the anonymization of the query"""
274
 
275
- print("------------ Step 3.2: Run in FHE on the Server Side")
276
 
277
- evaluation_key_path = KEYS_DIR / f"{USER_ID}/evaluation_key"
278
- encrypted_input_path = KEYS_DIR / f"{USER_ID}/encrypted_input"
279
 
280
- if not evaluation_key_path.is_file():
281
- error_message = (
282
- "Error Encountered While Sending Data to the Server: "
283
- f"The key has been generated correctly - {evaluation_key_path.is_file()=}"
284
- )
285
- return {anonymized_query_output: gr.update(value=error_message)}
286
 
287
- if not encrypted_input_path.is_file():
288
- error_message = (
289
- "Error Encountered While Sending Data to the Server: The data has not been encrypted "
290
- f"correctly on the client side - {encrypted_input_path.is_file()=}"
291
- )
292
- return {anonymized_query_output: gr.update(value=error_message)}
293
 
294
- data = {
295
- "user_id": USER_ID,
296
- }
 
 
 
 
 
 
297
 
298
- url = SERVER_URL + "run_fhe"
299
 
300
- with requests.post(
301
- url=url,
302
- data=data,
303
- ) as response:
304
- if not response.ok:
305
- return {
306
- anonymized_query_output: gr.update(
307
- value=(
308
- "⚠️ An error occurred on the Server Side. "
309
- "Please check connectivity and data transmission."
310
- ),
311
- ),
312
- }
313
- else:
314
- time.sleep(1)
315
- print(f"The query anonymization was computed in {response.json():.2f} s per token.")
316
 
 
 
 
317
 
318
- def get_output_fn() -> Dict:
 
 
 
 
 
 
 
 
 
 
319
 
320
- print("------------ Step 3.3: Get the output from the Server Side")
 
321
 
322
- if not (KEYS_DIR / f"{USER_ID}/evaluation_key").is_file():
323
- error_message = (
324
- "Error Encountered While Sending Data to the Server: "
325
- "The key has not been generated correctly"
326
- )
327
- return {anonymized_query_output: gr.update(value=error_message)}
328
 
329
- if not (KEYS_DIR / f"{USER_ID}/encrypted_input").is_file():
330
- error_message = (
331
- "Error Encountered While Sending Data to the Server: "
332
- "The data has not been encrypted correctly on the client side"
333
- )
334
- return {anonymized_query_output: gr.update(value=error_message)}
335
-
336
- data = {
337
- "user_id": USER_ID,
338
- }
339
-
340
- # Retrieve the encrypted output
341
- url = SERVER_URL + "get_output"
342
- with requests.post(
343
- url=url,
344
- data=data,
345
- ) as response:
346
- if response.ok:
347
- print("Data received βœ… from the remote Server")
348
- response_data = response.json()
349
- encrypted_output_base64 = response_data["encrypted_output"]
350
- length_encrypted_output_base64 = response_data["length"]
351
-
352
- # Decode the base64 encoded data
353
- encrypted_output = base64.b64decode(encrypted_output_base64)
354
- length_encrypted_output = base64.b64decode(length_encrypted_output_base64)
355
-
356
- # Save the encrypted output to bytes in a file as it is too large to pass through
357
- # regular Gradio buttons (see https://github.com/gradio-app/gradio/issues/1877)
358
-
359
- write_bytes(CLIENT_DIR / f"{USER_ID}_encrypted_output", encrypted_output)
360
- write_bytes(CLIENT_DIR / f"{USER_ID}_encrypted_output_len", length_encrypted_output)
361
-
362
- else:
363
- print("Error ❌ in getting data to the server")
364
-
365
-
366
- def decrypt_fn(text) -> Dict:
367
- """Dencrypt the data on the `Client Side`."""
368
-
369
- print("------------ Step 4: Dencrypt the data on the `Client Side`")
370
-
371
- # Get the encrypted output path
372
- encrypted_output_path = CLIENT_DIR / f"{USER_ID}_encrypted_output"
373
-
374
- if not encrypted_output_path.is_file():
375
- error_message = """⚠️ Please ensure that: \n
376
- - the connectivity \n
377
- - the query has been submitted \n
378
- - the evaluation key has been generated \n
379
- - the server processed the encrypted data \n
380
- - the Client received the data from the Server before decrypting the prediction
381
- """
382
- print(error_message)
383
 
384
- return error_message, None
 
 
 
 
 
 
385
 
386
- # Retrieve the client API
387
- client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{USER_ID}")
388
- client.load()
389
 
390
- # Load the encrypted output as bytes
391
- encrypted_output = read_bytes(CLIENT_DIR / f"{USER_ID}_encrypted_output")
392
- length = int.from_bytes(read_bytes(CLIENT_DIR / f"{USER_ID}_encrypted_output_len"), "big")
393
 
394
- tokens = re.findall(r"(\b[\w\.\/\-@]+\b|[\s,.!?;:'\"-]+)", text)
395
 
396
- decrypted_output, identified_words_with_prob = [], []
397
 
398
- i = 0
399
- for token in tokens:
400
 
401
- # Directly append non-word tokens or whitespace to processed_tokens
402
- if bool(re.match(r"^\s+$", token)):
403
- continue
404
- else:
405
- encrypted_token = encrypted_output[i : i + length]
406
- prediction_proba = client.deserialize_decrypt_dequantize(encrypted_token)
407
- probability = prediction_proba[0][1]
408
- i += length
409
 
410
- if probability >= 0.77:
411
- identified_words_with_prob.append((token, probability))
412
 
413
- # Use the existing UUID if available, otherwise generate a new one
414
- tmp_uuid = UUID_MAP.get(token, str(uuid.uuid4())[:8])
415
- decrypted_output.append(tmp_uuid)
416
- UUID_MAP[token] = tmp_uuid
417
- else:
418
- decrypted_output.append(token)
419
 
420
- # Update the UUID map with query.
421
- write_json(MAPPING_UUID_PATH, UUID_MAP)
422
 
423
- # Removing Spaces Before Punctuation:
424
- anonymized_text = re.sub(r"\s([,.!?;:])", r"\1", " ".join(decrypted_output))
 
 
 
425
 
426
- # Convert the list of identified words and probabilities into a DataFrame
427
- if identified_words_with_prob:
428
- identified_df = pd.DataFrame(
429
- identified_words_with_prob, columns=["Identified Words", "Probability"]
430
- )
431
- else:
432
- identified_df = pd.DataFrame(columns=["Identified Words", "Probability"])
433
 
434
- print("Decryption done βœ… on Client Side")
435
 
436
- return anonymized_text, identified_df
437
 
 
 
 
438
 
439
- def anonymization_with_fn(selected_sentences, query):
 
 
440
 
441
- encrypt_query_fn(query)
442
 
443
- send_input_fn(query)
 
 
 
 
 
 
 
 
 
444
 
445
- run_fhe_in_server_fn()
 
 
 
 
 
 
 
 
446
 
447
- get_output_fn()
 
 
448
 
449
- anonymized_text, identified_df = decrypt_fn(query)
 
 
450
 
451
- return {
452
- anonymized_doc_output: gr.update(value=select_static_anonymized_sentences_fn(selected_sentences)),
453
- anonymized_query_output: gr.update(value=anonymized_text),
454
- identified_words_output_df: gr.update(value=identified_df, visible=False),
455
- }
456
 
 
 
 
 
 
457
 
458
- def query_chatgpt_fn(anonymized_query, anonymized_document):
459
-
460
- print("------------ Step 5: ChatGPT communication")
461
-
462
- if not (KEYS_DIR / f"{USER_ID}/evaluation_key").is_file():
463
- error_message = "Error ❌: Please generate the key first!"
464
- return {chatgpt_response_anonymized: gr.update(value=error_message)}
465
-
466
- if not (CLIENT_DIR / f"{USER_ID}_encrypted_output").is_file():
467
- error_message = "Error ❌: Please encrypt your query first!"
468
- return {chatgpt_response_anonymized: gr.update(value=error_message)}
469
-
470
- context_prompt = read_txt(PROMPT_PATH)
471
-
472
- # Prepare prompt
473
- query = (
474
- "Document content:\n```\n"
475
- + anonymized_document
476
- + "\n\n```"
477
- + "Query:\n```\n"
478
- + anonymized_query
479
- + "\n```"
480
- )
481
- print(f'Prompt of CHATGPT:\n{query}')
482
-
483
- completion = client.chat.completions.create(
484
- model="gpt-4-1106-preview", # Replace with "gpt-4" if available
485
- messages=[
486
- {"role": "system", "content": context_prompt},
487
- {"role": "user", "content": query},
488
- ],
489
- )
490
- anonymized_response = completion.choices[0].message.content
491
- uuid_map = read_json(MAPPING_UUID_PATH)
492
-
493
- inverse_uuid_map = {
494
- v: k for k, v in uuid_map.items()
495
- } # TODO load the inverse mapping from disk for efficiency
496
-
497
- # Pattern to identify words and non-words (including punctuation, spaces, etc.)
498
- tokens = re.findall(r"(\b[\w\.\/\-@]+\b|[\s,.!?;:'\"-]+)", anonymized_response)
499
- processed_tokens = []
500
-
501
- for token in tokens:
502
- # Directly append non-word tokens or whitespace to processed_tokens
503
- if not token.strip() or not re.match(r"\w+", token):
504
- processed_tokens.append(token)
505
- continue
506
-
507
- if token in inverse_uuid_map:
508
- processed_tokens.append(inverse_uuid_map[token])
509
- else:
510
- processed_tokens.append(token)
511
- deanonymized_response = "".join(processed_tokens)
512
-
513
- return {chatgpt_response_anonymized: gr.update(value=anonymized_response),
514
- chatgpt_response_deanonymized: gr.update(value=deanonymized_response)}
515
 
516
 
517
 
 
85
  USER_ID = numpy.random.randint(0, 2**32)
86
 
87
 
88
+ # def select_static_anonymized_sentences_fn(selected_sentences: List):
89
 
90
+ # selected_sentences = [MAPPING_ANONYMIZED_SENTENCES[sentence] for sentence in selected_sentences]
91
 
92
+ # anonymized_selected_sentence = sorted(selected_sentences, key=lambda x: x[0])
93
 
94
+ # anonymized_selected_sentence = [sentence for _, sentence in anonymized_selected_sentence]
95
 
96
+ # return "\n\n".join(anonymized_selected_sentence)
97
 
98
 
99
+ # def key_gen_fn() -> Dict:
100
+ # """Generate keys for a given user."""
101
 
102
+ # print("------------ Step 1: Key Generation:")
103
 
104
+ # print(f"Your user ID is: {USER_ID}....")
105
 
106
 
107
+ # client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{USER_ID}")
108
+ # client.load()
109
 
110
+ # # Creates the private and evaluation keys on the client side
111
+ # client.generate_private_and_evaluation_keys()
112
 
113
+ # # Get the serialized evaluation keys
114
+ # serialized_evaluation_keys = client.get_serialized_evaluation_keys()
115
+ # assert isinstance(serialized_evaluation_keys, bytes)
116
 
117
+ # # Save the evaluation key
118
+ # evaluation_key_path = KEYS_DIR / f"{USER_ID}/evaluation_key"
119
 
120
+ # write_bytes(evaluation_key_path, serialized_evaluation_keys)
121
 
122
+ # # anonymizer.generate_key()
123
 
124
+ # if not evaluation_key_path.is_file():
125
+ # error_message = (
126
+ # f"Error Encountered While generating the evaluation {evaluation_key_path.is_file()=}"
127
+ # )
128
+ # print(error_message)
129
+ # return {gen_key_btn: gr.update(value=error_message)}
130
+ # else:
131
+ # print("Keys have been generated βœ…")
132
+ # return {gen_key_btn: gr.update(value="Keys have been generated βœ…")}
133
 
134
 
135
+ # def encrypt_doc_fn(doc):
136
 
137
+ # print(f"\n------------ Step 2.1: Doc encryption: {doc=}")
138
 
139
+ # if not (KEYS_DIR / f"{USER_ID}/evaluation_key").is_file():
140
+ # return {encrypted_doc_box: gr.update(value="Error ❌: Please generate the key first!", lines=10)}
141
 
142
+ # # Retrieve the client API
143
+ # client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{USER_ID}")
144
+ # client.load()
145
 
146
+ # encrypted_tokens = []
147
+ # tokens = re.findall(r"(\b[\w\.\/\-@]+\b|[\s,.!?;:'\"-]+|\$\d+(?:\.\d+)?|\€\d+(?:\.\d+)?)", ' '.join(doc))
148
 
149
+ # for token in tokens:
150
+ # if token.strip() and re.match(r"\w+", token):
151
+ # emb_x = MAPPING_DOC_EMBEDDING[token]
152
+ # assert emb_x.shape == (1, 1024)
153
+ # encrypted_x = client.quantize_encrypt_serialize(emb_x)
154
+ # assert isinstance(encrypted_x, bytes)
155
+ # encrypted_tokens.append(encrypted_x)
156
 
157
+ # print("Doc encrypted βœ… on Client Side")
158
 
159
+ # # No need to save it
160
+ # # write_bytes(KEYS_DIR / f"{USER_ID}/encrypted_doc", b"".join(encrypted_tokens))
161
 
162
+ # encrypted_quant_tokens_hex = [token.hex()[500:510] for token in encrypted_tokens]
163
 
164
+ # return {
165
+ # encrypted_doc_box: gr.update(value=" ".join(encrypted_quant_tokens_hex), lines=10),
166
+ # anonymized_doc_output: gr.update(visible=True, value=None),
167
+ # }
168
 
169
 
170
+ # def encrypt_query_fn(query):
171
 
172
+ # print(f"\n------------ Step 2: Query encryption: {query=}")
173
 
174
+ # if not (KEYS_DIR / f"{USER_ID}/evaluation_key").is_file():
175
+ # return {output_encrypted_box: gr.update(value="Error ❌: Please generate the key first!", lines=8)}
176
 
177
+ # if is_user_query_valid(query):
178
+ # return {
179
+ # query_box: gr.update(
180
+ # value=(
181
+ # "Unable to process ❌: The request exceeds the length limit or falls "
182
+ # "outside the scope of this document. Please refine your query."
183
+ # )
184
+ # )
185
+ # }
186
 
187
+ # # Retrieve the client API
188
+ # client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{USER_ID}")
189
+ # client.load()
190
 
191
+ # encrypted_tokens = []
192
 
193
+ # # Pattern to identify words and non-words (including punctuation, spaces, etc.)
194
+ # tokens = re.findall(r"(\b[\w\.\/\-@]+\b|[\s,.!?;:'\"-]+)", query)
195
 
196
+ # for token in tokens:
197
 
198
+ # # 1- Ignore non-words tokens
199
+ # if bool(re.match(r"^\s+$", token)):
200
+ # continue
201
 
202
+ # # 2- Directly append non-word tokens or whitespace to processed_tokens
203
 
204
+ # # Prediction for each word
205
+ # emb_x = get_batch_text_representation([token], EMBEDDINGS_MODEL, TOKENIZER)
206
+ # encrypted_x = client.quantize_encrypt_serialize(emb_x)
207
+ # assert isinstance(encrypted_x, bytes)
208
 
209
+ # encrypted_tokens.append(encrypted_x)
210
 
211
+ # print("Data encrypted βœ… on Client Side")
212
 
213
+ # assert len({len(token) for token in encrypted_tokens}) == 1
214
 
215
+ # write_bytes(KEYS_DIR / f"{USER_ID}/encrypted_input", b"".join(encrypted_tokens))
216
+ # write_bytes(
217
+ # KEYS_DIR / f"{USER_ID}/encrypted_input_len", len(encrypted_tokens[0]).to_bytes(10, "big")
218
+ # )
219
 
220
+ # encrypted_quant_tokens_hex = [token.hex()[500:580] for token in encrypted_tokens]
221
 
222
+ # return {
223
+ # output_encrypted_box: gr.update(value=" ".join(encrypted_quant_tokens_hex), lines=8),
224
+ # anonymized_query_output: gr.update(visible=True, value=None),
225
+ # identified_words_output_df: gr.update(visible=False, value=None),
226
+ # }
227
 
228
 
229
+ # def send_input_fn(query) -> Dict:
230
+ # """Send the encrypted data and the evaluation key to the server."""
231
 
232
+ # print("------------ Step 3.1: Send encrypted_data to the Server")
233
 
234
+ # evaluation_key_path = KEYS_DIR / f"{USER_ID}/evaluation_key"
235
+ # encrypted_input_path = KEYS_DIR / f"{USER_ID}/encrypted_input"
236
+ # encrypted_input_len_path = KEYS_DIR / f"{USER_ID}/encrypted_input_len"
237
 
238
+ # if not evaluation_key_path.is_file():
239
+ # error_message = (
240
+ # "Error Encountered While Sending Data to the Server: "
241
+ # f"The key has been generated correctly - {evaluation_key_path.is_file()=}"
242
+ # )
243
+ # return {anonymized_query_output: gr.update(value=error_message)}
244
+
245
+ # if not encrypted_input_path.is_file():
246
+ # error_message = (
247
+ # "Error Encountered While Sending Data to the Server: The data has not been encrypted "
248
+ # f"correctly on the client side - {encrypted_input_path.is_file()=}"
249
+ # )
250
+ # return {anonymized_query_output: gr.update(value=error_message)}
251
+
252
+ # # Define the data and files to post
253
+ # data = {"user_id": USER_ID, "input": query}
254
+
255
+ # files = [
256
+ # ("files", open(evaluation_key_path, "rb")),
257
+ # ("files", open(encrypted_input_path, "rb")),
258
+ # ("files", open(encrypted_input_len_path, "rb")),
259
+ # ]
260
+
261
+ # # Send the encrypted input and evaluation key to the server
262
+ # url = SERVER_URL + "send_input"
263
+
264
+ # with requests.post(
265
+ # url=url,
266
+ # data=data,
267
+ # files=files,
268
+ # ) as resp:
269
+ # print("Data sent to the server βœ…" if resp.ok else "Error ❌ in sending data to the server")
270
 
 
 
 
 
 
 
271
 
272
+ # def run_fhe_in_server_fn() -> Dict:
273
+ # """Run in FHE the anonymization of the query"""
274
+
275
+ # print("------------ Step 3.2: Run in FHE on the Server Side")
276
+
277
+ # evaluation_key_path = KEYS_DIR / f"{USER_ID}/evaluation_key"
278
+ # encrypted_input_path = KEYS_DIR / f"{USER_ID}/encrypted_input"
279
+
280
+ # if not evaluation_key_path.is_file():
281
+ # error_message = (
282
+ # "Error Encountered While Sending Data to the Server: "
283
+ # f"The key has been generated correctly - {evaluation_key_path.is_file()=}"
284
+ # )
285
+ # return {anonymized_query_output: gr.update(value=error_message)}
286
 
287
+ # if not encrypted_input_path.is_file():
288
+ # error_message = (
289
+ # "Error Encountered While Sending Data to the Server: The data has not been encrypted "
290
+ # f"correctly on the client side - {encrypted_input_path.is_file()=}"
291
+ # )
292
+ # return {anonymized_query_output: gr.update(value=error_message)}
293
+
294
+ # data = {
295
+ # "user_id": USER_ID,
296
+ # }
297
 
298
+ # url = SERVER_URL + "run_fhe"
299
+
300
+ # with requests.post(
301
+ # url=url,
302
+ # data=data,
303
+ # ) as response:
304
+ # if not response.ok:
305
+ # return {
306
+ # anonymized_query_output: gr.update(
307
+ # value=(
308
+ # "⚠️ An error occurred on the Server Side. "
309
+ # "Please check connectivity and data transmission."
310
+ # ),
311
+ # ),
312
+ # }
313
+ # else:
314
+ # time.sleep(1)
315
+ # print(f"The query anonymization was computed in {response.json():.2f} s per token.")
316
+
317
+
318
+ # def get_output_fn() -> Dict:
319
+
320
+ # print("------------ Step 3.3: Get the output from the Server Side")
321
+
322
+ # if not (KEYS_DIR / f"{USER_ID}/evaluation_key").is_file():
323
+ # error_message = (
324
+ # "Error Encountered While Sending Data to the Server: "
325
+ # "The key has not been generated correctly"
326
+ # )
327
+ # return {anonymized_query_output: gr.update(value=error_message)}
328
+
329
+ # if not (KEYS_DIR / f"{USER_ID}/encrypted_input").is_file():
330
+ # error_message = (
331
+ # "Error Encountered While Sending Data to the Server: "
332
+ # "The data has not been encrypted correctly on the client side"
333
+ # )
334
+ # return {anonymized_query_output: gr.update(value=error_message)}
335
+
336
+ # data = {
337
+ # "user_id": USER_ID,
338
+ # }
339
+
340
+ # # Retrieve the encrypted output
341
+ # url = SERVER_URL + "get_output"
342
+ # with requests.post(
343
+ # url=url,
344
+ # data=data,
345
+ # ) as response:
346
+ # if response.ok:
347
+ # print("Data received βœ… from the remote Server")
348
+ # response_data = response.json()
349
+ # encrypted_output_base64 = response_data["encrypted_output"]
350
+ # length_encrypted_output_base64 = response_data["length"]
351
 
352
+ # # Decode the base64 encoded data
353
+ # encrypted_output = base64.b64decode(encrypted_output_base64)
354
+ # length_encrypted_output = base64.b64decode(length_encrypted_output_base64)
355
+
356
+ # # Save the encrypted output to bytes in a file as it is too large to pass through
357
+ # # regular Gradio buttons (see https://github.com/gradio-app/gradio/issues/1877)
358
 
359
+ # write_bytes(CLIENT_DIR / f"{USER_ID}_encrypted_output", encrypted_output)
360
+ # write_bytes(CLIENT_DIR / f"{USER_ID}_encrypted_output_len", length_encrypted_output)
361
 
362
+ # else:
363
+ # print("Error ❌ in getting data to the server")
364
 
 
365
 
366
+ # def decrypt_fn(text) -> Dict:
367
+ # """Dencrypt the data on the `Client Side`."""
368
 
369
+ # print("------------ Step 4: Dencrypt the data on the `Client Side`")
 
 
 
 
 
370
 
371
+ # # Get the encrypted output path
372
+ # encrypted_output_path = CLIENT_DIR / f"{USER_ID}_encrypted_output"
 
 
 
 
373
 
374
+ # if not encrypted_output_path.is_file():
375
+ # error_message = """⚠️ Please ensure that: \n
376
+ # - the connectivity \n
377
+ # - the query has been submitted \n
378
+ # - the evaluation key has been generated \n
379
+ # - the server processed the encrypted data \n
380
+ # - the Client received the data from the Server before decrypting the prediction
381
+ # """
382
+ # print(error_message)
383
 
384
+ # return error_message, None
385
 
386
+ # # Retrieve the client API
387
+ # client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{USER_ID}")
388
+ # client.load()
389
+
390
+ # # Load the encrypted output as bytes
391
+ # encrypted_output = read_bytes(CLIENT_DIR / f"{USER_ID}_encrypted_output")
392
+ # length = int.from_bytes(read_bytes(CLIENT_DIR / f"{USER_ID}_encrypted_output_len"), "big")
 
 
 
 
 
 
 
 
 
393
 
394
+ # tokens = re.findall(r"(\b[\w\.\/\-@]+\b|[\s,.!?;:'\"-]+)", text)
395
+
396
+ # decrypted_output, identified_words_with_prob = [], []
397
 
398
+ # i = 0
399
+ # for token in tokens:
400
+
401
+ # # Directly append non-word tokens or whitespace to processed_tokens
402
+ # if bool(re.match(r"^\s+$", token)):
403
+ # continue
404
+ # else:
405
+ # encrypted_token = encrypted_output[i : i + length]
406
+ # prediction_proba = client.deserialize_decrypt_dequantize(encrypted_token)
407
+ # probability = prediction_proba[0][1]
408
+ # i += length
409
 
410
+ # if probability >= 0.77:
411
+ # identified_words_with_prob.append((token, probability))
412
 
413
+ # # Use the existing UUID if available, otherwise generate a new one
414
+ # tmp_uuid = UUID_MAP.get(token, str(uuid.uuid4())[:8])
415
+ # decrypted_output.append(tmp_uuid)
416
+ # UUID_MAP[token] = tmp_uuid
417
+ # else:
418
+ # decrypted_output.append(token)
419
 
420
+ # # Update the UUID map with query.
421
+ # write_json(MAPPING_UUID_PATH, UUID_MAP)
422
+
423
+ # # Removing Spaces Before Punctuation:
424
+ # anonymized_text = re.sub(r"\s([,.!?;:])", r"\1", " ".join(decrypted_output))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
 
426
+ # # Convert the list of identified words and probabilities into a DataFrame
427
+ # if identified_words_with_prob:
428
+ # identified_df = pd.DataFrame(
429
+ # identified_words_with_prob, columns=["Identified Words", "Probability"]
430
+ # )
431
+ # else:
432
+ # identified_df = pd.DataFrame(columns=["Identified Words", "Probability"])
433
 
434
+ # print("Decryption done βœ… on Client Side")
 
 
435
 
436
+ # return anonymized_text, identified_df
 
 
437
 
 
438
 
439
+ # def anonymization_with_fn(selected_sentences, query):
440
 
441
+ # encrypt_query_fn(query)
 
442
 
443
+ # send_input_fn(query)
 
 
 
 
 
 
 
444
 
445
+ # run_fhe_in_server_fn()
 
446
 
447
+ # get_output_fn()
 
 
 
 
 
448
 
449
+ # anonymized_text, identified_df = decrypt_fn(query)
 
450
 
451
+ # return {
452
+ # anonymized_doc_output: gr.update(value=select_static_anonymized_sentences_fn(selected_sentences)),
453
+ # anonymized_query_output: gr.update(value=anonymized_text),
454
+ # identified_words_output_df: gr.update(value=identified_df, visible=False),
455
+ # }
456
 
 
 
 
 
 
 
 
457
 
458
+ # def query_chatgpt_fn(anonymized_query, anonymized_document):
459
 
460
+ # print("------------ Step 5: ChatGPT communication")
461
 
462
+ # if not (KEYS_DIR / f"{USER_ID}/evaluation_key").is_file():
463
+ # error_message = "Error ❌: Please generate the key first!"
464
+ # return {chatgpt_response_anonymized: gr.update(value=error_message)}
465
 
466
+ # if not (CLIENT_DIR / f"{USER_ID}_encrypted_output").is_file():
467
+ # error_message = "Error ❌: Please encrypt your query first!"
468
+ # return {chatgpt_response_anonymized: gr.update(value=error_message)}
469
 
470
+ # context_prompt = read_txt(PROMPT_PATH)
471
 
472
+ # # Prepare prompt
473
+ # query = (
474
+ # "Document content:\n```\n"
475
+ # + anonymized_document
476
+ # + "\n\n```"
477
+ # + "Query:\n```\n"
478
+ # + anonymized_query
479
+ # + "\n```"
480
+ # )
481
+ # print(f'Prompt of CHATGPT:\n{query}')
482
 
483
+ # completion = client.chat.completions.create(
484
+ # model="gpt-4-1106-preview", # Replace with "gpt-4" if available
485
+ # messages=[
486
+ # {"role": "system", "content": context_prompt},
487
+ # {"role": "user", "content": query},
488
+ # ],
489
+ # )
490
+ # anonymized_response = completion.choices[0].message.content
491
+ # uuid_map = read_json(MAPPING_UUID_PATH)
492
 
493
+ # inverse_uuid_map = {
494
+ # v: k for k, v in uuid_map.items()
495
+ # } # TODO load the inverse mapping from disk for efficiency
496
 
497
+ # # Pattern to identify words and non-words (including punctuation, spaces, etc.)
498
+ # tokens = re.findall(r"(\b[\w\.\/\-@]+\b|[\s,.!?;:'\"-]+)", anonymized_response)
499
+ # processed_tokens = []
500
 
501
+ # for token in tokens:
502
+ # # Directly append non-word tokens or whitespace to processed_tokens
503
+ # if not token.strip() or not re.match(r"\w+", token):
504
+ # processed_tokens.append(token)
505
+ # continue
506
 
507
+ # if token in inverse_uuid_map:
508
+ # processed_tokens.append(inverse_uuid_map[token])
509
+ # else:
510
+ # processed_tokens.append(token)
511
+ # deanonymized_response = "".join(processed_tokens)
512
 
513
+ # return {chatgpt_response_anonymized: gr.update(value=anonymized_response),
514
+ # chatgpt_response_deanonymized: gr.update(value=deanonymized_response)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
515
 
516
 
517