Christina-A-Pan commited on
Commit
b77ac12
1 Parent(s): 51bb6f7

When the end user clicks "Save Reports," submits all reports to the AVID API

Browse files
Files changed (2) hide show
  1. audit_utils.py +90 -0
  2. server.py +22 -0
audit_utils.py CHANGED
@@ -23,6 +23,7 @@ import time
23
  from sentence_transformers import SentenceTransformer, util
24
  import torch
25
  from bertopic import BERTopic
 
26
 
27
  ########################################
28
  # PRE-LOADING
@@ -316,6 +317,95 @@ def get_grp_model_labels(n_label_per_bin, score_bins, grp_ids):
316
 
317
  return ratings_grp
318
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  ########################################
320
  # GET_PERSONALIZED_MODEL utils
321
  def fetch_existing_data(user, model_name):
 
23
  from sentence_transformers import SentenceTransformer, util
24
  import torch
25
  from bertopic import BERTopic
26
+ from datetime import date
27
 
28
  ########################################
29
  # PRE-LOADING
 
317
 
318
  return ratings_grp
319
 
320
+ ########################################
321
+ # SAVE_REPORT utils
322
+ # Convert indielabel json to AVID json format.
323
+ # See the AVID format in https://avidml.org/avidtools/reference/report
324
+ #
325
+ # Important mappings:
326
+ # IndieLabel Attribute AVID Attribute Example
327
+ # text_entry description "I think the Perspective API
328
+ # is too sensitive. Here are some examples."
329
+ # topic feature 0_shes_woman_lady_face
330
+ # persp_score model_score 0.94
331
+ # comment ori_input "She looks beautiful"
332
+ # user_rating personal_model_score 0.92
333
+ # user_decision user_decision "Non-toxic"
334
+ # Note that this is at the individual report level.
335
+ def convert_indie_label_json_to_avid_json(indie_label_json):
336
+
337
+ # Setting up the structure with a dict to enable programmatic additions
338
+ avid_json_dict = {
339
+ "data_type": "AVID",
340
+ "data_version": None,
341
+ "metadata": None,
342
+ "affects": {
343
+ "developer": [],
344
+ "deployer": [
345
+ "Hugging Face"
346
+ ],
347
+ # TODO: Make artifacts malleable during modularity work
348
+ "artifacts": [
349
+ {
350
+ "type": "Model",
351
+ "name": "Perspective API"
352
+ }
353
+ ]
354
+ },
355
+ "problemtype": {
356
+ "classof": "Undefined", # I don't think any of the other ClassEnums are applicable. Link: https://avidml.org/avidtools/_modules/avidtools/datamodels/enums#ClassEnum
357
+ "type": "Detection",
358
+ "description": {
359
+ "lang": "eng", # TODO: Make language selectable
360
+ "value": "This report contains results from an end user audit conducted on Hugging Face."
361
+ }
362
+ },
363
+ "metrics": [ # Note: For the end users use case, I made each comment an example.
364
+ ],
365
+ "references": [],
366
+ "description": {
367
+ "lang": "eng", # TODO: Make language selectable
368
+ "value": "" # Leaving empty so the report comments can be contained here.
369
+ },
370
+ "impact": {
371
+ "avid": {
372
+ "risk_domain": [
373
+ "Ethics"
374
+ ],
375
+ "sep_view": [
376
+ "E0101: Group fairness"
377
+ ],
378
+ "lifecycle_view": [
379
+ "L05: Evaluation"
380
+ ],
381
+ "taxonomy_version": "0.2"
382
+ }
383
+ },
384
+ "credit": None,
385
+ "reported_date": "" # Leaving empty so that it can be dynamically filled in
386
+ }
387
+
388
+ avid_json_dict["description"] = indie_label_json["text_entry"]
389
+ avid_json_dict["reported_date"] = str(date.today())
390
+ for e in indie_label_json["evidence"]:
391
+ curr_metric = {}
392
+ curr_metric["name"] = "Perspective API"
393
+ curr_metric["detection_method"] = {
394
+ "type": "Detection",
395
+ "name": "Individual Example from End User Audit"
396
+ }
397
+ res_dict = {}
398
+ res_dict["feature"] = e["topic"]
399
+ res_dict["model_score"] = str(e["persp_score"]) # Converted to string to avoid Float type error with DB
400
+ res_dict["ori_input"] = e["comment"]
401
+ res_dict["personal_model_score"] = str(e["user_rating"]) # See above
402
+ res_dict["user_decision"] = e["user_decision"]
403
+ curr_metric["results"] = res_dict
404
+ avid_json_dict["metrics"].append(curr_metric)
405
+
406
+ new_report = json.dumps(avid_json_dict)
407
+ return new_report
408
+
409
  ########################################
410
  # GET_PERSONALIZED_MODEL utils
411
  def fetch_existing_data(user, model_name):
server.py CHANGED
@@ -21,6 +21,9 @@ import friendlywords as fw
21
 
22
  import audit_utils as utils
23
 
 
 
 
24
  app = Flask(__name__)
25
  DEBUG = False # Debug flag for development; set to False for production
26
 
@@ -631,6 +634,21 @@ def get_prompts_scaffold():
631
  },
632
  ]
633
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
  ########################################
635
  # ROUTE: /SAVE_REPORTS
636
  @app.route("/save_reports")
@@ -641,6 +659,9 @@ def save_reports():
641
  scaffold_method = request.args.get("scaffold_method")
642
  model = request.args.get("model")
643
 
 
 
 
644
  # Save reports for current user to file
645
  reports_file = utils.get_reports_file(cur_user, model)
646
  with open(reports_file, "w", encoding ='utf8') as f:
@@ -649,6 +670,7 @@ def save_reports():
649
  results = {
650
  "status": "success",
651
  }
 
652
  return json.dumps(results)
653
 
654
  ########################################
 
21
 
22
  import audit_utils as utils
23
 
24
+ import requests
25
+
26
+
27
  app = Flask(__name__)
28
  DEBUG = False # Debug flag for development; set to False for production
29
 
 
634
  },
635
  ]
636
 
637
+ # Submit all reports to AVID
638
+ # Logs the responses
639
+ def submit_reports_to_AVID(reports):
640
+ #Set up the connection to AVID
641
+ root = environ.get('AVID_API_URL')
642
+ api_key = environ.get('AVID_API_KEY')
643
+ key = {"Authorization": api_key}
644
+
645
+ for r in reports:
646
+ new_report = utils.convert_indie_label_json_to_avid_json(r)
647
+ url = root + "submit"
648
+ response = requests.post(url, json=json.loads(new_report), headers=key) # The loads ensures type compliance
649
+ uuid = response.json()
650
+ print("AVID API response:", response, uuid)
651
+
652
  ########################################
653
  # ROUTE: /SAVE_REPORTS
654
  @app.route("/save_reports")
 
659
  scaffold_method = request.args.get("scaffold_method")
660
  model = request.args.get("model")
661
 
662
+ # Submit reports to AVID
663
+ submit_reports_to_AVID(reports)
664
+
665
  # Save reports for current user to file
666
  reports_file = utils.get_reports_file(cur_user, model)
667
  with open(reports_file, "w", encoding ='utf8') as f:
 
670
  results = {
671
  "status": "success",
672
  }
673
+ print(results)
674
  return json.dumps(results)
675
 
676
  ########################################