Spaces:
Runtime error
Runtime error
Merge remote-tracking branch 'upstream/main'
Browse files- README.md +1 -1
- audit_utils.py +12 -9
- indie_label_svelte/package-lock.json +0 -0
- indie_label_svelte/package.json +5 -5
- indie_label_svelte/public/global.css +24 -2
- indie_label_svelte/public/img/anderson.jpeg +0 -0
- indie_label_svelte/public/img/bernstein.jpeg +0 -0
- indie_label_svelte/public/img/blili_hamelin.jpeg +0 -0
- indie_label_svelte/public/img/butters.jpeg +0 -0
- indie_label_svelte/public/img/gordon.jpeg +0 -0
- indie_label_svelte/public/img/hancock.png +0 -0
- indie_label_svelte/public/img/lam.jpg +0 -0
- indie_label_svelte/public/img/landay.jpeg +0 -0
- indie_label_svelte/public/img/metaxa.jpg +0 -0
- indie_label_svelte/public/img/pan.jpg +0 -0
- indie_label_svelte/public/img/temp.png +0 -0
- indie_label_svelte/public/index.html +9 -3
- indie_label_svelte/rollup.config.js +0 -1
- indie_label_svelte/src/About.svelte +225 -0
- indie_label_svelte/src/Auditing.svelte +0 -3
- indie_label_svelte/src/ClusterResults.svelte +4 -4
- indie_label_svelte/src/HypothesisPanel.svelte +84 -50
- indie_label_svelte/src/MainPanel.svelte +22 -7
- indie_label_svelte/src/ModelPerf.svelte +1 -1
- indie_label_svelte/src/OverallResults.svelte +1 -4
- indie_label_svelte/src/SubmitReportDialog.svelte +30 -21
- server.py +18 -4
README.md
CHANGED
@@ -15,7 +15,7 @@ This repo shares our implementation of **IndieLabel**—an interactive web appli
|
|
15 |
```
|
16 |
$ pip install -r requirements.txt
|
17 |
```
|
18 |
-
- Download and unzip the `data` sub-directory from [this Drive folder](https://drive.google.com/file/d/
|
19 |
|
20 |
|
21 |
- Start the Flask server:
|
|
|
15 |
```
|
16 |
$ pip install -r requirements.txt
|
17 |
```
|
18 |
+
- Download and unzip the `data` sub-directory from [this Drive folder](https://drive.google.com/file/d/1iYueqzG9qIB45HT_5iwJp-44Dhfm2XbR/view?usp=sharing) and place it in the repo directory (39.7MB zipped, 124.3MB unzipped).
|
19 |
|
20 |
|
21 |
- Start the Flask server:
|
audit_utils.py
CHANGED
@@ -336,6 +336,10 @@ def format_description(indie_label_json):
|
|
336 |
text_entry = indie_label_json["text_entry"]
|
337 |
return f"Title: {title}\nError Type: {error_type}\nSummary/Suggestions: {text_entry}"
|
338 |
|
|
|
|
|
|
|
|
|
339 |
# Convert indielabel json to AVID json format.
|
340 |
# See the AVID format in https://avidml.org/avidtools/reference/report
|
341 |
#
|
@@ -349,7 +353,7 @@ def format_description(indie_label_json):
|
|
349 |
# user_rating personal_model_score 0.92
|
350 |
# user_decision user_decision "Non-toxic"
|
351 |
# Note that this is at the individual report level.
|
352 |
-
def convert_indie_label_json_to_avid_json(indie_label_json, cur_user, email, sep_selection):
|
353 |
|
354 |
# Setting up the structure with a dict to enable programmatic additions
|
355 |
avid_json_dict = {
|
@@ -398,17 +402,16 @@ def convert_indie_label_json_to_avid_json(indie_label_json, cur_user, email, sep
|
|
398 |
"taxonomy_version": "0.2"
|
399 |
}
|
400 |
},
|
401 |
-
"credit":
|
|
|
|
|
|
|
402 |
"reported_date": "" # Leaving empty so that it can be dynamically filled in
|
403 |
}
|
404 |
|
405 |
-
avid_json_dict["description"] = format_description(indie_label_json)
|
406 |
-
avid_json_dict["reported_date"] = str(date.today())
|
407 |
-
|
408 |
-
if email != "":
|
409 |
-
avid_json_dict["credit"] = email
|
410 |
-
else:
|
411 |
-
avid_json_dict["credit"] = cur_user
|
412 |
|
413 |
sep_enum = get_sep_enum(sep_selection)
|
414 |
avid_json_dict["impact"]["avid"]["sep_view"] = [sep_enum]
|
|
|
336 |
text_entry = indie_label_json["text_entry"]
|
337 |
return f"Title: {title}\nError Type: {error_type}\nSummary/Suggestions: {text_entry}"
|
338 |
|
339 |
+
# Format the credit field for the report with the current user's username, optional name, and optional email address
|
340 |
+
def format_credit(cur_user, name, email):
|
341 |
+
return f"Username: {cur_user}, Name: {name}, Email: {email}"
|
342 |
+
|
343 |
# Convert indielabel json to AVID json format.
|
344 |
# See the AVID format in https://avidml.org/avidtools/reference/report
|
345 |
#
|
|
|
353 |
# user_rating personal_model_score 0.92
|
354 |
# user_decision user_decision "Non-toxic"
|
355 |
# Note that this is at the individual report level.
|
356 |
+
def convert_indie_label_json_to_avid_json(indie_label_json, cur_user, name, email, sep_selection):
|
357 |
|
358 |
# Setting up the structure with a dict to enable programmatic additions
|
359 |
avid_json_dict = {
|
|
|
402 |
"taxonomy_version": "0.2"
|
403 |
}
|
404 |
},
|
405 |
+
"credit": {
|
406 |
+
"lang": "eng", # TODO: Make language selectable
|
407 |
+
"value": "" # Leaving empty so that credit can be assigned
|
408 |
+
},
|
409 |
"reported_date": "" # Leaving empty so that it can be dynamically filled in
|
410 |
}
|
411 |
|
412 |
+
avid_json_dict["description"]["value"] = format_description(indie_label_json)
|
413 |
+
avid_json_dict["reported_date"] = str(date.today())
|
414 |
+
avid_json_dict["credit"]["value"] = format_credit(cur_user, name, email)
|
|
|
|
|
|
|
|
|
415 |
|
416 |
sep_enum = get_sep_enum(sep_selection)
|
417 |
avid_json_dict["impact"]["avid"]["sep_view"] = [sep_enum]
|
indie_label_svelte/package-lock.json
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
indie_label_svelte/package.json
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
{
|
2 |
-
"name": "
|
3 |
"version": "0.0.0",
|
4 |
-
"author": "
|
5 |
-
"repository": "[email protected]:
|
6 |
"bugs": {
|
7 |
-
"url": "https://github.com/
|
8 |
},
|
9 |
"private": true,
|
10 |
"scripts": {
|
@@ -25,7 +25,7 @@
|
|
25 |
"@smui/checkbox": "^6.0.0-beta.2",
|
26 |
"@smui/chips": "^6.0.0-beta.2",
|
27 |
"@smui/circular-progress": "^6.0.0-beta.4",
|
28 |
-
"@smui/common": "^6.
|
29 |
"@smui/data-table": "^6.0.0-beta.2",
|
30 |
"@smui/drawer": "^6.0.0-beta.4",
|
31 |
"@smui/form-field": "^6.0.0-beta.2",
|
|
|
1 |
{
|
2 |
+
"name": "indie-label",
|
3 |
"version": "0.0.0",
|
4 |
+
"author": "Michelle Lam <michelle123lam@gmail.com> (http://michelle123lam.github.io)",
|
5 |
+
"repository": "[email protected]:StanfordHCI/indie-label.git",
|
6 |
"bugs": {
|
7 |
+
"url": "https://github.com/StanfordHCI/indie-label/issues"
|
8 |
},
|
9 |
"private": true,
|
10 |
"scripts": {
|
|
|
25 |
"@smui/checkbox": "^6.0.0-beta.2",
|
26 |
"@smui/chips": "^6.0.0-beta.2",
|
27 |
"@smui/circular-progress": "^6.0.0-beta.4",
|
28 |
+
"@smui/common": "^6.1.4",
|
29 |
"@smui/data-table": "^6.0.0-beta.2",
|
30 |
"@smui/drawer": "^6.0.0-beta.4",
|
31 |
"@smui/form-field": "^6.0.0-beta.2",
|
indie_label_svelte/public/global.css
CHANGED
@@ -120,7 +120,7 @@ h6 {
|
|
120 |
font-weight: bold;
|
121 |
font-size: 16px;
|
122 |
margin-top: 25px;
|
123 |
-
margin-bottom:
|
124 |
}
|
125 |
|
126 |
.head_6_non_cap {
|
@@ -204,6 +204,11 @@ table {
|
|
204 |
margin: 60px 0;
|
205 |
}
|
206 |
|
|
|
|
|
|
|
|
|
|
|
207 |
.page_title {
|
208 |
font-size: 30px;
|
209 |
font-weight: bold;
|
@@ -319,4 +324,21 @@ table {
|
|
319 |
|
320 |
.mdc-drawer .mdc-deprecated-list-item {
|
321 |
height: 64px !important;
|
322 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
font-weight: bold;
|
121 |
font-size: 16px;
|
122 |
margin-top: 25px;
|
123 |
+
margin-bottom: 15px;
|
124 |
}
|
125 |
|
126 |
.head_6_non_cap {
|
|
|
204 |
margin: 60px 0;
|
205 |
}
|
206 |
|
207 |
+
.spacing_vert_100_bottom {
|
208 |
+
margin: 0 0 100px 0;
|
209 |
+
}
|
210 |
+
|
211 |
+
|
212 |
.page_title {
|
213 |
font-size: 30px;
|
214 |
font-weight: bold;
|
|
|
324 |
|
325 |
.mdc-drawer .mdc-deprecated-list-item {
|
326 |
height: 64px !important;
|
327 |
+
}
|
328 |
+
|
329 |
+
/* Material UI secondary button formatting */
|
330 |
+
:root {
|
331 |
+
--mdc-theme-secondary: #676778;
|
332 |
+
}
|
333 |
+
.smui-button--color-secondary:not(:disabled) {
|
334 |
+
color: var(--mdc-theme-secondary) !important;
|
335 |
+
}
|
336 |
+
.smui-button--color-secondary.mdc-button--outlined:not(:disabled) {
|
337 |
+
border-color: var(--mdc-theme-secondary) !important;
|
338 |
+
}
|
339 |
+
.smui-button--color-secondary .mdc-button__ripple::before, .smui-button--color-secondary .mdc-button__ripple::after {
|
340 |
+
background-color: var(--mdc-theme-secondary) !important;
|
341 |
+
}
|
342 |
+
.smui-button--color-secondary:not(:disabled) .mdc-button__icon {
|
343 |
+
color: var(--mdc-theme-secondary) !important;
|
344 |
+
}
|
indie_label_svelte/public/img/anderson.jpeg
ADDED
![]() |
indie_label_svelte/public/img/bernstein.jpeg
ADDED
![]() |
indie_label_svelte/public/img/blili_hamelin.jpeg
ADDED
![]() |
indie_label_svelte/public/img/butters.jpeg
ADDED
![]() |
indie_label_svelte/public/img/gordon.jpeg
ADDED
![]() |
indie_label_svelte/public/img/hancock.png
ADDED
![]() |
indie_label_svelte/public/img/lam.jpg
ADDED
![]() |
indie_label_svelte/public/img/landay.jpeg
ADDED
![]() |
indie_label_svelte/public/img/metaxa.jpg
ADDED
![]() |
indie_label_svelte/public/img/pan.jpg
ADDED
![]() |
indie_label_svelte/public/img/temp.png
ADDED
![]() |
indie_label_svelte/public/index.html
CHANGED
@@ -10,9 +10,6 @@
|
|
10 |
<link rel='icon' type='image/png' href='/favicon.png'>
|
11 |
<link rel='stylesheet' href='/global.css'>
|
12 |
<link rel='stylesheet' href='/build/bundle.css'>
|
13 |
-
<link rel='stylesheet' href='/build/extra.css'>
|
14 |
-
<!-- <link rel="stylesheet" href="../node_modules/svelte-material-ui/bare.css" /> -->
|
15 |
-
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/bare.min.css" /> -->
|
16 |
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
17 |
|
18 |
<link
|
@@ -22,6 +19,15 @@
|
|
22 |
|
23 |
<script defer src='/build/bundle.js'></script>
|
24 |
</head>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
<body>
|
27 |
</body>
|
|
|
10 |
<link rel='icon' type='image/png' href='/favicon.png'>
|
11 |
<link rel='stylesheet' href='/global.css'>
|
12 |
<link rel='stylesheet' href='/build/bundle.css'>
|
|
|
|
|
|
|
13 |
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
14 |
|
15 |
<link
|
|
|
19 |
|
20 |
<script defer src='/build/bundle.js'></script>
|
21 |
</head>
|
22 |
+
<!-- Google tag (gtag.js) -->
|
23 |
+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-GFB1D1ZXRZ"></script>
|
24 |
+
<script>
|
25 |
+
window.dataLayer = window.dataLayer || [];
|
26 |
+
function gtag(){dataLayer.push(arguments);}
|
27 |
+
gtag('js', new Date());
|
28 |
+
|
29 |
+
gtag('config', 'G-GFB1D1ZXRZ');
|
30 |
+
</script>
|
31 |
|
32 |
<body>
|
33 |
</body>
|
indie_label_svelte/rollup.config.js
CHANGED
@@ -51,7 +51,6 @@ export default {
|
|
51 |
// we'll extract any component CSS out into
|
52 |
// a separate file - better for performance
|
53 |
css({ output: "bundle.css" }),
|
54 |
-
// css({ output: 'public/build/extra.css' }),
|
55 |
|
56 |
// If you have external dependencies installed from
|
57 |
// npm, you'll most likely need these plugins. In
|
|
|
51 |
// we'll extract any component CSS out into
|
52 |
// a separate file - better for performance
|
53 |
css({ output: "bundle.css" }),
|
|
|
54 |
|
55 |
// If you have external dependencies installed from
|
56 |
// npm, you'll most likely need these plugins. In
|
indie_label_svelte/src/About.svelte
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
</script>
|
3 |
+
|
4 |
+
<svelte:head>
|
5 |
+
<title>About</title>
|
6 |
+
</svelte:head>
|
7 |
+
|
8 |
+
<div class="panel">
|
9 |
+
<div class="panel_contents">
|
10 |
+
<div>
|
11 |
+
<h3>IndieLabel Tutorial</h3>
|
12 |
+
<p class="body">
|
13 |
+
Check out this 5-minute video tutorial for a quick overview of the IndieLabel tool. If you prefer a written document, you can also find a help article <a href="https://docs.google.com/document/d/1BTo8LFUriiZcSWCcQy0lel9VxGl4KZtlFnu7wAFaiu4/edit?usp=sharing" target="_blank">here</a>.
|
14 |
+
</p>
|
15 |
+
<div class="video-container">
|
16 |
+
<iframe src="https://www.youtube.com/embed/Je0DCDnJ6KQ?si=H1dVy-oe6PSP0QYM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
17 |
+
</div>
|
18 |
+
</div>
|
19 |
+
<div>
|
20 |
+
<h3>About IndieLabel</h3>
|
21 |
+
<p class="body">
|
22 |
+
The IndieLabel deployment on this Hugging Face Space is a collaboration between researchers at the <a href="https://hci.stanford.edu/" target="_blank">Stanford HCI Group</a> and <a href="https://avidml.org/arva/" target="_blank">ARVA (AI Risk and Vulnerability Alliance)</a>. The IndieLabel tool is a research prototype designed to empower everyday users to lead large-scale investigations of harmful algorithmic behavior, and this Space is intended as a public-facing deployment of this prototype.
|
23 |
+
</p>
|
24 |
+
|
25 |
+
<div class="card-container">
|
26 |
+
<p class="head_5">IndieLabel & the End-User Audits paper</p>
|
27 |
+
<p class="body">
|
28 |
+
The <a href="https://github.com/StanfordHCI/indie-label" target="_blank">IndieLabel</a> tool was initially presented as a research prototype in an academic publication called <b><i>End-User Audits: A System Empowering Communities to Lead Large-Scale Investigations of Harmful Algorithmic Behavior</i></b>. IndieLabel aids users in rapidly identifying where they disagree with a system's behavior with the help of a personalized recommender system model.
|
29 |
+
</p>
|
30 |
+
<p class="body">
|
31 |
+
The key question underlying the End-User Audits paper is: <i>how do we enable everyday users to lead large-scale algorithm audits</i>? The full paper was presented at CSCW 2022 and is available on the <a href="https://dl.acm.org/doi/10.1145/3555625" target="_blank">ACM Digital Library</a> or via <a href="https://hci.stanford.edu/publications/2022/Lam_EndUserAudits_CSCW22.pdf" target="_blank">Stanford HCI</a>. The End-User Audits paper abstract summarizes our core motivation, approach, and findings:
|
32 |
+
</p>
|
33 |
+
<p class="body blockquote">
|
34 |
+
"Because algorithm audits are conducted by technical experts, audits are necessarily limited to the hypotheses that experts think to test. End users hold the promise to expand this purview, as they inhabit spaces and witness algorithmic impacts that auditors do not. In pursuit of this goal, we propose end-user audits—system-scale audits led by non-technical users—and present an approach that scaffolds end users in hypothesis generation, evidence identification, and results communication. Today, performing a system-scale audit requires substantial user effort to label thousands of system outputs, so we introduce a collaborative filtering technique that leverages the algorithmic system's own disaggregated training data to project from a small number of end user labels onto the full test set. Our end-user auditing tool, IndieLabel, employs these predicted labels so that users can rapidly explore where their opinions diverge from the algorithmic system's outputs. By highlighting topic areas where the system is under-performing for the user and surfacing sets of likely error cases, the tool guides the user in authoring an audit report. In an evaluation of end-user audits on a popular comment toxicity model with 17 non-technical participants, participants both replicated issues that formal audits had previously identified and also raised previously underreported issues such as under-flagging on veiled forms of hate that perpetuate stigma and over-flagging of slurs that have been reclaimed by marginalized communities."
|
35 |
+
</p>
|
36 |
+
|
37 |
+
|
38 |
+
<p class="body">
|
39 |
+
The End-User Audits work was led by Stanford PhD student Michelle Lam along with co-authors Mitchell Gordon, Danaë Metaxa, Jeffrey Hancock, James Landay, and Michael Bernstein.
|
40 |
+
</p>
|
41 |
+
|
42 |
+
<div class="image-container">
|
43 |
+
<div>
|
44 |
+
<img src="./img/lam.jpg" alt="Michelle Lam">
|
45 |
+
<p>
|
46 |
+
<a href="http://michelle123lam.github.io" target="_blank"><b>Michelle Lam</b></a><br>
|
47 |
+
PhD Student, Stanford CS
|
48 |
+
</p>
|
49 |
+
</div>
|
50 |
+
<div>
|
51 |
+
<img src="./img/gordon.jpeg" alt="Mitchell Gordon">
|
52 |
+
<p>
|
53 |
+
<a href="https://mgordon.me/" target="_blank"><b>Mitchell Gordon</b></a><br/>
|
54 |
+
Incoming Asst Professor, MIT EECS
|
55 |
+
</p>
|
56 |
+
</div>
|
57 |
+
<div>
|
58 |
+
<img src="./img/metaxa.jpg" alt="Danaë Metaxa">
|
59 |
+
<p>
|
60 |
+
<a href="https://metaxa.net/" target="_blank"><b>Danaë Metaxa</b></a><br/>
|
61 |
+
Asst Professor, UPenn CIS
|
62 |
+
</p>
|
63 |
+
</div>
|
64 |
+
<div>
|
65 |
+
<img src="./img/hancock.png" alt="Jeffrey Hancock">
|
66 |
+
<p>
|
67 |
+
<a href="https://sml.stanford.edu/people/jeff-hancock" target="_blank"><b>Jeffrey Hancock</b></a><br/>
|
68 |
+
Professor, Stanford Comm
|
69 |
+
</p>
|
70 |
+
</div>
|
71 |
+
<div>
|
72 |
+
<img src="./img/landay.jpeg" alt="James Landay">
|
73 |
+
<p>
|
74 |
+
<a href="https://www.landay.org/" target="_blank"><b>James Landay</b></a><br/>
|
75 |
+
Professor, Stanford CS
|
76 |
+
</p>
|
77 |
+
</div>
|
78 |
+
<div>
|
79 |
+
<img src="./img/bernstein.jpeg" alt="Michael Bernstein">
|
80 |
+
<p>
|
81 |
+
<a href="https://hci.stanford.edu/msb/" target="_blank"><b>Michael Bernstein</b></a><br/>
|
82 |
+
Assoc Professor, Stanford CS
|
83 |
+
</p>
|
84 |
+
</div>
|
85 |
+
</div>
|
86 |
+
</div>
|
87 |
+
|
88 |
+
<div class="card-container">
|
89 |
+
<p class="head_5">ARVA</p>
|
90 |
+
<p class="body">
|
91 |
+
The <a href="https://avidml.org/arva/" target="_blank">AI Risk and Vulnerability Alliance (ARVA)</a> is a nonprofit organization focused on making AI safer for everyone. Our mission is to empower communities to recognize, diagnose, and manage vulnerabilities in AI that affects them. Our flagship project is the <a href="https://avidml.org" target="_blank">AI Vulnerability Database (AVID)</a>, is an open-source knowledge base of failure modes for AI models, datasets, and systems.
|
92 |
+
</p>
|
93 |
+
</div>
|
94 |
+
|
95 |
+
<div class="card-container">
|
96 |
+
<p class="head_5">The Team</p>
|
97 |
+
<p class="body">
|
98 |
+
The IndieLabel Hugging Face deployment was made possible by a wonderful team of volunteers who worked on adapting IndieLabel for use by a general audience, connecting its reports to AVID (AI Vulnerability Database), and deploying it on Hugging Face Spaces. The team includes:
|
99 |
+
</p>
|
100 |
+
<div>
|
101 |
+
<div class="image-container-wide">
|
102 |
+
<div class="image-wide">
|
103 |
+
<img src="./img/lam.jpg" alt="Michelle Lam">
|
104 |
+
<p>
|
105 |
+
<a href="http://michelle123lam.github.io" target="_blank"><b>Michelle Lam</b></a><br>
|
106 |
+
Michelle Lam is a PhD Candidate at Stanford University in the HCI Group. Her research focuses on building systems that empower everyday users to surface their expertise to design and evaluate AI systems.
|
107 |
+
</p>
|
108 |
+
</div>
|
109 |
+
<div class="image-wide">
|
110 |
+
<img src="./img/anderson.jpeg" alt="Carol Anderson">
|
111 |
+
<p>
|
112 |
+
<a href="https://www.carol-anderson.com/" target="_blank"><b>Carol Anderson</b></a><br>
|
113 |
+
Carol Anderson is a data scientist and machine learning practitioner with expertise in natural language processing (NLP), biological data, and AI ethics. She serves as AVID’s machine learning lead.
|
114 |
+
</p>
|
115 |
+
</div>
|
116 |
+
<div class="image-wide">
|
117 |
+
<img src="./img/pan.jpg" alt="Christina Pan">
|
118 |
+
<p>
|
119 |
+
<a href="https://www.christinaapan.com/" target="_blank"><b>Christina Pan</b></a><br>
|
120 |
+
Christina Pan started her career building machine learning (ML) models at Google, which inspired her passion for design thinking and AI ethics.
|
121 |
+
</p>
|
122 |
+
</div>
|
123 |
+
<div class="image-wide">
|
124 |
+
<img src="./img/butters.jpeg" alt="Nathan Butters">
|
125 |
+
<p>
|
126 |
+
<b>Nathan Butters</b><br>
|
127 |
+
Nathan Butters is a product manager in the Office of Ethical and Humane Use at Salesforce. He is a cofounder of the AI Risk and Vulnerability Alliance (ARVA).
|
128 |
+
</p>
|
129 |
+
</div>
|
130 |
+
<div class="image-wide">
|
131 |
+
<img src="./img/blili_hamelin.jpeg" alt="Borhane Blili-Hamelin">
|
132 |
+
<p>
|
133 |
+
<a href="https://borhane.xyz/" target="_blank"><b>Borhane Blili-Hamelin</b></a><br>
|
134 |
+
Borhane Blili-Hamelin is an ethicist, researcher and AI risk management consultant. He is an officer at the AI Risk and Vulnerability Alliance (ARVA), an affiliate at Data & Society, and a senior consultant at BABL AI.
|
135 |
+
</p>
|
136 |
+
</div>
|
137 |
+
</div>
|
138 |
+
</div>
|
139 |
+
</div>
|
140 |
+
</div>
|
141 |
+
</div>
|
142 |
+
</div>
|
143 |
+
|
144 |
+
<style>
|
145 |
+
a {
|
146 |
+
color: #333;
|
147 |
+
text-decoration: underline;
|
148 |
+
}
|
149 |
+
|
150 |
+
.panel {
|
151 |
+
margin: 0 40px;
|
152 |
+
}
|
153 |
+
|
154 |
+
.blockquote {
|
155 |
+
margin: 0 40px;
|
156 |
+
}
|
157 |
+
|
158 |
+
.head_5 {
|
159 |
+
margin: 10px 0;
|
160 |
+
}
|
161 |
+
|
162 |
+
.card-container {
|
163 |
+
margin: 40px 0;
|
164 |
+
}
|
165 |
+
|
166 |
+
.image-container {
|
167 |
+
margin: 20px 0;
|
168 |
+
display: flex;
|
169 |
+
flex-wrap: wrap;
|
170 |
+
justify-content: center;
|
171 |
+
gap: 20px; /* Adjust the gap between images */
|
172 |
+
}
|
173 |
+
|
174 |
+
.image-container img {
|
175 |
+
max-width: 110px; /* Adjust the maximum width of images */
|
176 |
+
height: 110px;
|
177 |
+
border-radius: 50%;
|
178 |
+
display: block;
|
179 |
+
}
|
180 |
+
|
181 |
+
.image-container p {
|
182 |
+
text-align: center;
|
183 |
+
margin-top: 5px; /* Adjust the margin between image and name */
|
184 |
+
max-width: 110px;
|
185 |
+
font-size: 11px;
|
186 |
+
}
|
187 |
+
|
188 |
+
.image-container-wide {
|
189 |
+
margin: 20px 0;
|
190 |
+
display: flex;
|
191 |
+
flex-direction: column;
|
192 |
+
justify-content: center;
|
193 |
+
gap: 20px;
|
194 |
+
}
|
195 |
+
|
196 |
+
.image-wide {
|
197 |
+
display: flex;
|
198 |
+
flex-direction: row;
|
199 |
+
align-items: center;
|
200 |
+
gap: 10px;
|
201 |
+
}
|
202 |
+
|
203 |
+
.image-container-wide img {
|
204 |
+
max-width: 110px; /* Adjust the maximum width of images */
|
205 |
+
height: 110px;
|
206 |
+
border-radius: 50%;
|
207 |
+
display: block;
|
208 |
+
}
|
209 |
+
|
210 |
+
.video-container {
|
211 |
+
position: relative;
|
212 |
+
padding-bottom: 10px;
|
213 |
+
padding-top: 10px;
|
214 |
+
height: 40vh;
|
215 |
+
overflow: hidden;
|
216 |
+
}
|
217 |
+
|
218 |
+
.video-container iframe {
|
219 |
+
position: absolute;
|
220 |
+
top: 0;
|
221 |
+
left: 0;
|
222 |
+
width: 100%;
|
223 |
+
height: 100%;
|
224 |
+
}
|
225 |
+
</style>
|
indie_label_svelte/src/Auditing.svelte
CHANGED
@@ -293,9 +293,6 @@
|
|
293 |
{#if audit_results}
|
294 |
<OverallResults
|
295 |
data={audit_results}
|
296 |
-
clusters={clusters}
|
297 |
-
personalized_model={personalized_model}
|
298 |
-
cluster={topic}
|
299 |
/>
|
300 |
{/if}
|
301 |
{:catch error}
|
|
|
293 |
{#if audit_results}
|
294 |
<OverallResults
|
295 |
data={audit_results}
|
|
|
|
|
|
|
296 |
/>
|
297 |
{/if}
|
298 |
{:catch error}
|
indie_label_svelte/src/ClusterResults.svelte
CHANGED
@@ -32,7 +32,7 @@
|
|
32 |
export let show_checkboxes = true;
|
33 |
export let table_width_pct = 80;
|
34 |
export let rowsPerPage = 10;
|
35 |
-
export let evidence;
|
36 |
export let table_id;
|
37 |
export let use_model = true;
|
38 |
export let show_agree_disagree = false;
|
@@ -232,7 +232,7 @@
|
|
232 |
<div class="row">
|
233 |
<div class="col s8">
|
234 |
<VegaLite
|
235 |
-
{cluster_overview_data}
|
236 |
spec={cluster_overview_spec}
|
237 |
bind:view={cluster_overview_view}
|
238 |
/>
|
@@ -302,7 +302,7 @@
|
|
302 |
<Cell>
|
303 |
System<br>decision<br>
|
304 |
{#if show_checkboxes}
|
305 |
-
<span style="font-size:
|
306 |
{/if}
|
307 |
</Cell>
|
308 |
{#if show_num_ratings}
|
@@ -314,7 +314,7 @@
|
|
314 |
<Cell>
|
315 |
Potential error<br>type<br>
|
316 |
{#if show_checkboxes}
|
317 |
-
<span style="font-size:
|
318 |
{/if}
|
319 |
</Cell>
|
320 |
|
|
|
32 |
export let show_checkboxes = true;
|
33 |
export let table_width_pct = 80;
|
34 |
export let rowsPerPage = 10;
|
35 |
+
export let evidence = null;
|
36 |
export let table_id;
|
37 |
export let use_model = true;
|
38 |
export let show_agree_disagree = false;
|
|
|
232 |
<div class="row">
|
233 |
<div class="col s8">
|
234 |
<VegaLite
|
235 |
+
data={cluster_overview_data}
|
236 |
spec={cluster_overview_spec}
|
237 |
bind:view={cluster_overview_view}
|
238 |
/>
|
|
|
302 |
<Cell>
|
303 |
System<br>decision<br>
|
304 |
{#if show_checkboxes}
|
305 |
+
<span style="font-size:9px; max-width:125px">White = Non-toxic, <br>Grey = Toxic</span>
|
306 |
{/if}
|
307 |
</Cell>
|
308 |
{#if show_num_ratings}
|
|
|
314 |
<Cell>
|
315 |
Potential error<br>type<br>
|
316 |
{#if show_checkboxes}
|
317 |
+
<span style="font-size:9px; max-width:125px">Darker red = Greater <br>potential system error</span>
|
318 |
{/if}
|
319 |
</Cell>
|
320 |
|
indie_label_svelte/src/HypothesisPanel.svelte
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
<script lang="ts">
|
2 |
import { onMount } from "svelte";
|
|
|
3 |
import ClusterResults from "./ClusterResults.svelte";
|
4 |
import SubmitReportDialog from "./SubmitReportDialog.svelte";
|
5 |
|
6 |
import Button, { Label } from "@smui/button";
|
7 |
import Textfield from '@smui/textfield';
|
|
|
8 |
import { new_evidence } from './stores/new_evidence_store.js';
|
9 |
import { open_evidence } from './stores/open_evidence_store.js';
|
10 |
import { topic_chosen } from './stores/cur_topic_store.js';
|
@@ -22,6 +24,7 @@
|
|
22 |
import Checkbox from '@smui/checkbox';
|
23 |
import FormField from '@smui/form-field';
|
24 |
import IconButton from "@smui/icon-button";
|
|
|
25 |
import Radio from '@smui/radio';
|
26 |
|
27 |
export let model;
|
@@ -50,6 +53,8 @@
|
|
50 |
let editTitle = false;
|
51 |
let editErrorType = false;
|
52 |
let unfinished_count = 0;
|
|
|
|
|
53 |
|
54 |
function setActive(value: string) {
|
55 |
selected = value;
|
@@ -90,7 +95,8 @@
|
|
90 |
selected = all_reports[0];
|
91 |
setActive(selected);
|
92 |
cur_open_evidence = selected["evidence"];
|
93 |
-
unfinished_count = all_reports.filter(item => !item.
|
|
|
94 |
return all_reports;
|
95 |
}
|
96 |
|
@@ -129,7 +135,11 @@
|
|
129 |
|
130 |
let promise_save = Promise.resolve(null);
|
131 |
function handleSaveReport() {
|
|
|
132 |
promise_save = saveReport();
|
|
|
|
|
|
|
133 |
}
|
134 |
|
135 |
async function saveReport() {
|
@@ -143,6 +153,8 @@
|
|
143 |
const response = await fetch("./save_reports?" + params);
|
144 |
const text = await response.text();
|
145 |
const data = JSON.parse(text);
|
|
|
|
|
146 |
return data;
|
147 |
}
|
148 |
|
@@ -152,15 +164,14 @@
|
|
152 |
error_type: "",
|
153 |
evidence: [],
|
154 |
text_entry: "",
|
155 |
-
|
156 |
};
|
157 |
all_reports = all_reports.concat(new_report);
|
158 |
promise = Promise.resolve(all_reports);
|
159 |
// Open this new report
|
160 |
selected = all_reports[all_reports.length - 1];
|
161 |
cur_open_evidence = selected["evidence"];
|
162 |
-
|
163 |
-
unfinished_count = all_reports.filter(item => !item.complete_status).length
|
164 |
}
|
165 |
|
166 |
function handleDeleteReport() {
|
@@ -169,13 +180,11 @@
|
|
169 |
promise = Promise.resolve(all_reports);
|
170 |
selected = all_reports[0];
|
171 |
cur_open_evidence = selected["evidence"];
|
172 |
-
unfinished_count = all_reports.filter(item => !item.
|
173 |
}
|
174 |
|
175 |
-
function
|
176 |
-
|
177 |
-
unfinished_count = all_reports.filter(item => !item.complete_status).length
|
178 |
-
handleSaveReport(); // Auto-save report
|
179 |
}
|
180 |
|
181 |
// Error type
|
@@ -208,6 +217,14 @@
|
|
208 |
editErrorType = false;
|
209 |
}
|
210 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
211 |
let promise_submit = Promise.resolve(null);
|
212 |
function handleSubmitReport() {
|
213 |
promise_submit = submitReport();
|
@@ -231,8 +248,8 @@
|
|
231 |
<div class="panel_header">
|
232 |
<div class="panel_header_content">
|
233 |
<div class="page_header">
|
234 |
-
<img src="/logo.png" style="height: 50px;
|
235 |
-
<Button class="user_button" color="secondary" style="margin:
|
236 |
<Label>User: {cur_user}</Label>
|
237 |
</Button>
|
238 |
</div>
|
@@ -242,7 +259,7 @@
|
|
242 |
on:click={() => (open = !open)}
|
243 |
color="primary"
|
244 |
disabled={model == null}
|
245 |
-
style="float: right; padding:
|
246 |
>
|
247 |
{#if open}
|
248 |
<Label>Close</Label>
|
@@ -284,7 +301,7 @@
|
|
284 |
on:click={() => setActive(report)}
|
285 |
activated={selected === report}
|
286 |
>
|
287 |
-
{#if report["
|
288 |
<Graphic class="material-icons" aria-hidden="true">task_alt</Graphic>
|
289 |
{:else}
|
290 |
<Graphic class="material-icons" aria-hidden="true">radio_button_unchecked</Graphic>
|
@@ -412,7 +429,7 @@
|
|
412 |
{/key}
|
413 |
</div>
|
414 |
|
415 |
-
<div class="
|
416 |
<div class="head_6">
|
417 |
<b>Summary/Suggestions</b>
|
418 |
</div>
|
@@ -430,14 +447,17 @@
|
|
430 |
|
431 |
</div>
|
432 |
|
433 |
-
<div class="spacing_vert_40">
|
434 |
<div class="head_6">
|
435 |
-
<b>
|
436 |
-
|
437 |
-
|
438 |
-
|
|
|
|
|
|
|
|
|
439 |
</div>
|
440 |
-
|
441 |
</div>
|
442 |
</div>
|
443 |
{/if}
|
@@ -452,55 +472,58 @@
|
|
452 |
|
453 |
<div class="panel_footer">
|
454 |
<div class="panel_footer_contents">
|
|
|
455 |
<Button
|
456 |
on:click={handleNewReport}
|
457 |
variant="outlined"
|
458 |
-
color="secondary"
|
459 |
-
style=""
|
460 |
>
|
461 |
<Label>New</Label>
|
462 |
</Button>
|
463 |
|
|
|
464 |
<!-- <Button
|
465 |
on:click={handleDeleteReport}
|
466 |
variant="outlined"
|
467 |
-
color="secondary"
|
468 |
-
style=""
|
469 |
>
|
470 |
<Label>Delete</Label>
|
471 |
</Button> -->
|
472 |
|
|
|
473 |
<Button
|
474 |
on:click={handleSaveReport}
|
475 |
variant="outlined"
|
476 |
-
color="secondary"
|
477 |
>
|
478 |
-
<Label>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
479 |
</Button>
|
480 |
|
|
|
|
|
481 |
<Button
|
482 |
on:click={handleSubmitReport}
|
483 |
variant="outlined"
|
484 |
-
color="secondary"
|
485 |
>
|
486 |
-
<Label>Send Reports</Label>
|
487 |
</Button>
|
|
|
|
|
488 |
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
{:then result}
|
494 |
-
{#if result}
|
495 |
-
{new Date().toLocaleTimeString()}
|
496 |
-
{:else}
|
497 |
-
—
|
498 |
-
{/if}
|
499 |
-
{:catch error}
|
500 |
-
<p style="color: red">{error.message}</p>
|
501 |
-
{/await}
|
502 |
-
</i></span>
|
503 |
-
</div>
|
504 |
</div>
|
505 |
</div>
|
506 |
{/if}
|
@@ -534,13 +557,23 @@
|
|
534 |
background: #f3f3f3;
|
535 |
z-index: 11;
|
536 |
bottom: 0;
|
537 |
-
padding:
|
538 |
}
|
539 |
.panel_footer_contents {
|
540 |
-
/* padding: 0px 20px; */
|
541 |
display: flex;
|
542 |
justify-content: space-around;
|
543 |
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
544 |
}
|
545 |
|
546 |
:global(.mdc-button.user_button) {
|
@@ -551,18 +584,17 @@
|
|
551 |
|
552 |
:global(.mdc-button.user_button span) {
|
553 |
text-overflow: ellipsis;
|
554 |
-
white-space: nowrap;
|
555 |
overflow: hidden;
|
556 |
}
|
557 |
|
558 |
.page_header {
|
559 |
width: 100%;
|
560 |
background: #e3d6fd;
|
561 |
-
/* padding: 21px 0; */
|
562 |
-
/* border-bottom: 1px solid #e3d6fd; */
|
563 |
padding: 10.5px 0;
|
564 |
position: relative;
|
565 |
-
display:
|
|
|
|
|
566 |
}
|
567 |
|
568 |
.page_header:before {
|
@@ -575,9 +607,11 @@
|
|
575 |
}
|
576 |
|
577 |
.hypotheses_header {
|
578 |
-
display: inline-block;
|
579 |
width: 100%;
|
580 |
padding: 10px 0;
|
581 |
vertical-align: middle;
|
|
|
|
|
|
|
582 |
}
|
583 |
</style>
|
|
|
1 |
<script lang="ts">
|
2 |
import { onMount } from "svelte";
|
3 |
+
import { fade } from 'svelte/transition';
|
4 |
import ClusterResults from "./ClusterResults.svelte";
|
5 |
import SubmitReportDialog from "./SubmitReportDialog.svelte";
|
6 |
|
7 |
import Button, { Label } from "@smui/button";
|
8 |
import Textfield from '@smui/textfield';
|
9 |
+
import Select, { Option } from "@smui/select";
|
10 |
import { new_evidence } from './stores/new_evidence_store.js';
|
11 |
import { open_evidence } from './stores/open_evidence_store.js';
|
12 |
import { topic_chosen } from './stores/cur_topic_store.js';
|
|
|
24 |
import Checkbox from '@smui/checkbox';
|
25 |
import FormField from '@smui/form-field';
|
26 |
import IconButton from "@smui/icon-button";
|
27 |
+
import { Icon } from "@smui/common";
|
28 |
import Radio from '@smui/radio';
|
29 |
|
30 |
export let model;
|
|
|
53 |
let editTitle = false;
|
54 |
let editErrorType = false;
|
55 |
let unfinished_count = 0;
|
56 |
+
let has_complete_report = false;
|
57 |
+
let save_check_visible = false; // Whether the save checkmark is visible
|
58 |
|
59 |
function setActive(value: string) {
|
60 |
selected = value;
|
|
|
95 |
selected = all_reports[0];
|
96 |
setActive(selected);
|
97 |
cur_open_evidence = selected["evidence"];
|
98 |
+
unfinished_count = all_reports.filter(item => (item.evidence.length == 0) || (item.text_entry == "") || !(item.sep_selection)).length
|
99 |
+
has_complete_report = hasCompleteReport();
|
100 |
return all_reports;
|
101 |
}
|
102 |
|
|
|
135 |
|
136 |
let promise_save = Promise.resolve(null);
|
137 |
function handleSaveReport() {
|
138 |
+
// Briefly display checkmark
|
139 |
promise_save = saveReport();
|
140 |
+
save_check_visible = true;
|
141 |
+
// Hide save checkmark after 1 second
|
142 |
+
setTimeout(() => save_check_visible = false, 1000);
|
143 |
}
|
144 |
|
145 |
async function saveReport() {
|
|
|
153 |
const response = await fetch("./save_reports?" + params);
|
154 |
const text = await response.text();
|
155 |
const data = JSON.parse(text);
|
156 |
+
|
157 |
+
has_complete_report = hasCompleteReport();
|
158 |
return data;
|
159 |
}
|
160 |
|
|
|
164 |
error_type: "",
|
165 |
evidence: [],
|
166 |
text_entry: "",
|
167 |
+
sep_selection: "",
|
168 |
};
|
169 |
all_reports = all_reports.concat(new_report);
|
170 |
promise = Promise.resolve(all_reports);
|
171 |
// Open this new report
|
172 |
selected = all_reports[all_reports.length - 1];
|
173 |
cur_open_evidence = selected["evidence"];
|
174 |
+
unfinished_count = all_reports.filter(item => (item.evidence.length == 0) || (item.text_entry == "") || !(item.sep_selection)).length
|
|
|
175 |
}
|
176 |
|
177 |
function handleDeleteReport() {
|
|
|
180 |
promise = Promise.resolve(all_reports);
|
181 |
selected = all_reports[0];
|
182 |
cur_open_evidence = selected["evidence"];
|
183 |
+
unfinished_count = all_reports.filter(item => (item.evidence.length == 0) || (item.text_entry == "") || !(item.sep_selection)).length
|
184 |
}
|
185 |
|
186 |
+
function hasCompleteReport() {
|
187 |
+
return all_reports.some(item => (item.evidence.length > 0) && (item.text_entry != "") && (item.sep_selection));
|
|
|
|
|
188 |
}
|
189 |
|
190 |
// Error type
|
|
|
217 |
editErrorType = false;
|
218 |
}
|
219 |
|
220 |
+
// SEP selection
|
221 |
+
let all_sep_options = [
|
222 |
+
"Accuracy",
|
223 |
+
"Bias/Discrimination",
|
224 |
+
"Adversarial Example",
|
225 |
+
"Other",
|
226 |
+
];
|
227 |
+
|
228 |
let promise_submit = Promise.resolve(null);
|
229 |
function handleSubmitReport() {
|
230 |
promise_submit = submitReport();
|
|
|
248 |
<div class="panel_header">
|
249 |
<div class="panel_header_content">
|
250 |
<div class="page_header">
|
251 |
+
<img src="/logo.png" style="height: 50px;" alt="IndieLabel" />
|
252 |
+
<Button class="user_button" color="secondary" style="margin: 0 5px; padding: 0 5px;" >
|
253 |
<Label>User: {cur_user}</Label>
|
254 |
</Button>
|
255 |
</div>
|
|
|
259 |
on:click={() => (open = !open)}
|
260 |
color="primary"
|
261 |
disabled={model == null}
|
262 |
+
style="float: right; padding: 0 5px; margin: 0 5px; max-width: 200px;"
|
263 |
>
|
264 |
{#if open}
|
265 |
<Label>Close</Label>
|
|
|
301 |
on:click={() => setActive(report)}
|
302 |
activated={selected === report}
|
303 |
>
|
304 |
+
{#if (report["evidence"].length > 0) && (report["text_entry"] != "") && (report["sep_selection"])}
|
305 |
<Graphic class="material-icons" aria-hidden="true">task_alt</Graphic>
|
306 |
{:else}
|
307 |
<Graphic class="material-icons" aria-hidden="true">radio_button_unchecked</Graphic>
|
|
|
429 |
{/key}
|
430 |
</div>
|
431 |
|
432 |
+
<div class="spacing_vert_40">
|
433 |
<div class="head_6">
|
434 |
<b>Summary/Suggestions</b>
|
435 |
</div>
|
|
|
447 |
|
448 |
</div>
|
449 |
|
450 |
+
<div class="spacing_vert_40 spacing_vert_100_bottom">
|
451 |
<div class="head_6">
|
452 |
+
<b>Audit Category</b>
|
453 |
+
</div>
|
454 |
+
<div>
|
455 |
+
<Select bind:value={selected["sep_selection"]} label="Audit category" style="width: 90%">
|
456 |
+
{#each all_sep_options as opt}
|
457 |
+
<Option value={opt}>{opt}</Option>
|
458 |
+
{/each}
|
459 |
+
</Select>
|
460 |
</div>
|
|
|
461 |
</div>
|
462 |
</div>
|
463 |
{/if}
|
|
|
472 |
|
473 |
<div class="panel_footer">
|
474 |
<div class="panel_footer_contents">
|
475 |
+
<!-- New button -->
|
476 |
<Button
|
477 |
on:click={handleNewReport}
|
478 |
variant="outlined"
|
|
|
|
|
479 |
>
|
480 |
<Label>New</Label>
|
481 |
</Button>
|
482 |
|
483 |
+
<!-- Delete button -->
|
484 |
<!-- <Button
|
485 |
on:click={handleDeleteReport}
|
486 |
variant="outlined"
|
|
|
|
|
487 |
>
|
488 |
<Label>Delete</Label>
|
489 |
</Button> -->
|
490 |
|
491 |
+
<!-- Save button -->
|
492 |
<Button
|
493 |
on:click={handleSaveReport}
|
494 |
variant="outlined"
|
|
|
495 |
>
|
496 |
+
<Label>
|
497 |
+
{#await promise_save}
|
498 |
+
<CircularProgress style="height: 13.5px; width: 13.5px;" indeterminate />
|
499 |
+
{:then result}
|
500 |
+
{#if result && save_check_visible}
|
501 |
+
<span transition:fade>
|
502 |
+
<Icon class="material-icons">check</Icon>
|
503 |
+
</span>
|
504 |
+
{/if}
|
505 |
+
{:catch error}
|
506 |
+
<span style="color: red">{error.message}</span>
|
507 |
+
{/await}
|
508 |
+
Save
|
509 |
+
</Label>
|
510 |
</Button>
|
511 |
|
512 |
+
<!-- Send to Avid button -->
|
513 |
+
{#key has_complete_report}
|
514 |
<Button
|
515 |
on:click={handleSubmitReport}
|
516 |
variant="outlined"
|
|
|
517 |
>
|
518 |
+
<Label>Send Reports to AVID</Label>
|
519 |
</Button>
|
520 |
+
{/key}
|
521 |
+
</div>
|
522 |
|
523 |
+
<div class="feedback_section">
|
524 |
+
<a href="https://forms.gle/vDXchpbBFjDeKjJA6" target="_blank" class="feedback_link">
|
525 |
+
Share feedback about the tool
|
526 |
+
</a>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
527 |
</div>
|
528 |
</div>
|
529 |
{/if}
|
|
|
557 |
background: #f3f3f3;
|
558 |
z-index: 11;
|
559 |
bottom: 0;
|
560 |
+
padding: 5px 0px;
|
561 |
}
|
562 |
.panel_footer_contents {
|
|
|
563 |
display: flex;
|
564 |
justify-content: space-around;
|
565 |
align-items: center;
|
566 |
+
padding: 5px 0px 10px 0px;
|
567 |
+
}
|
568 |
+
.feedback_section {
|
569 |
+
display: flex;
|
570 |
+
justify-content: space-around;
|
571 |
+
align-items: center;
|
572 |
+
}
|
573 |
+
.feedback_link {
|
574 |
+
color: var(--mdc-theme-secondary);
|
575 |
+
font-size: 10px;
|
576 |
+
text-decoration: underline;
|
577 |
}
|
578 |
|
579 |
:global(.mdc-button.user_button) {
|
|
|
584 |
|
585 |
:global(.mdc-button.user_button span) {
|
586 |
text-overflow: ellipsis;
|
|
|
587 |
overflow: hidden;
|
588 |
}
|
589 |
|
590 |
.page_header {
|
591 |
width: 100%;
|
592 |
background: #e3d6fd;
|
|
|
|
|
593 |
padding: 10.5px 0;
|
594 |
position: relative;
|
595 |
+
display: flex;
|
596 |
+
align-items: center;
|
597 |
+
justify-content: space-around;
|
598 |
}
|
599 |
|
600 |
.page_header:before {
|
|
|
607 |
}
|
608 |
|
609 |
.hypotheses_header {
|
|
|
610 |
width: 100%;
|
611 |
padding: 10px 0;
|
612 |
vertical-align: middle;
|
613 |
+
display: flex;
|
614 |
+
align-items: center;
|
615 |
+
justify-content: space-around;
|
616 |
}
|
617 |
</style>
|
indie_label_svelte/src/MainPanel.svelte
CHANGED
@@ -1,20 +1,26 @@
|
|
1 |
<script lang="ts">
|
2 |
import Labeling from "./Labeling.svelte";
|
3 |
import Auditing from "./Auditing.svelte";
|
|
|
4 |
|
5 |
import Tab, { Label } from "@smui/tab";
|
6 |
import TabBar from "@smui/tab-bar";
|
|
|
7 |
|
8 |
-
export let model;
|
9 |
export let error_type;
|
10 |
export let cur_user;
|
11 |
|
12 |
// Handle routing
|
13 |
-
let active = "
|
14 |
let searchParams = new URLSearchParams(window.location.search);
|
15 |
let tab = searchParams.get("tab");
|
16 |
if (tab == "auditing") {
|
17 |
active = "auditing";
|
|
|
|
|
|
|
|
|
18 |
}
|
19 |
|
20 |
</script>
|
@@ -25,22 +31,31 @@
|
|
25 |
|
26 |
<div class="auditing_panel">
|
27 |
<div class="tab_header">
|
28 |
-
<TabBar tabs={["labeling", "auditing"]} let:tab bind:active>
|
29 |
-
<Tab {tab}>
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
31 |
</Tab>
|
32 |
</TabBar>
|
33 |
</div>
|
34 |
|
35 |
<div class="panel_contents">
|
36 |
<div>
|
37 |
-
<div id="labeling" hidden={active
|
38 |
<Labeling cur_user={cur_user}/>
|
39 |
</div>
|
40 |
|
41 |
-
<div id="auditing" hidden={active
|
42 |
<Auditing bind:personalized_model={model} bind:cur_error_type={error_type} cur_user={cur_user} on:change/>
|
43 |
</div>
|
|
|
|
|
|
|
|
|
44 |
</div>
|
45 |
|
46 |
</div>
|
|
|
1 |
<script lang="ts">
|
2 |
import Labeling from "./Labeling.svelte";
|
3 |
import Auditing from "./Auditing.svelte";
|
4 |
+
import About from "./About.svelte";
|
5 |
|
6 |
import Tab, { Label } from "@smui/tab";
|
7 |
import TabBar from "@smui/tab-bar";
|
8 |
+
import { Icon } from "@smui/common";
|
9 |
|
10 |
+
export let model = null;
|
11 |
export let error_type;
|
12 |
export let cur_user;
|
13 |
|
14 |
// Handle routing
|
15 |
+
let active = "about"; // default tab on load
|
16 |
let searchParams = new URLSearchParams(window.location.search);
|
17 |
let tab = searchParams.get("tab");
|
18 |
if (tab == "auditing") {
|
19 |
active = "auditing";
|
20 |
+
} else if (tab == "about") {
|
21 |
+
active = "about";
|
22 |
+
} else if (tab == "labeling") {
|
23 |
+
active = "labeling";
|
24 |
}
|
25 |
|
26 |
</script>
|
|
|
31 |
|
32 |
<div class="auditing_panel">
|
33 |
<div class="tab_header">
|
34 |
+
<TabBar tabs={["labeling", "auditing", "about"]} let:tab bind:active>
|
35 |
+
<Tab {tab} minWidth={tab == "about"}>
|
36 |
+
{#if tab == "about"}
|
37 |
+
<Icon class="material-icons">info_outlined</Icon>
|
38 |
+
{:else}
|
39 |
+
<Label>{tab}</Label>
|
40 |
+
{/if}
|
41 |
+
|
42 |
</Tab>
|
43 |
</TabBar>
|
44 |
</div>
|
45 |
|
46 |
<div class="panel_contents">
|
47 |
<div>
|
48 |
+
<div id="labeling" hidden={active != "labeling"} >
|
49 |
<Labeling cur_user={cur_user}/>
|
50 |
</div>
|
51 |
|
52 |
+
<div id="auditing" hidden={active != "auditing"} >
|
53 |
<Auditing bind:personalized_model={model} bind:cur_error_type={error_type} cur_user={cur_user} on:change/>
|
54 |
</div>
|
55 |
+
|
56 |
+
<div id="about" hidden={active != "about"} >
|
57 |
+
<About />
|
58 |
+
</div>
|
59 |
</div>
|
60 |
|
61 |
</div>
|
indie_label_svelte/src/ModelPerf.svelte
CHANGED
@@ -32,7 +32,7 @@
|
|
32 |
<div>
|
33 |
<!-- Performance visualization -->
|
34 |
<div>
|
35 |
-
<VegaLite {perf_plot_data} spec={perf_plot_spec} bind:view={perf_plot_view}/>
|
36 |
</div>
|
37 |
</div>
|
38 |
</div>
|
|
|
32 |
<div>
|
33 |
<!-- Performance visualization -->
|
34 |
<div>
|
35 |
+
<VegaLite data={perf_plot_data} spec={perf_plot_spec} bind:view={perf_plot_view}/>
|
36 |
</div>
|
37 |
</div>
|
38 |
</div>
|
indie_label_svelte/src/OverallResults.svelte
CHANGED
@@ -7,9 +7,6 @@
|
|
7 |
import Card, { Content } from '@smui/card';
|
8 |
|
9 |
export let data;
|
10 |
-
export let clusters;
|
11 |
-
export let personalized_model;
|
12 |
-
export let cluster = "";
|
13 |
|
14 |
let show_step1_info = false;
|
15 |
|
@@ -68,7 +65,7 @@
|
|
68 |
{/if}
|
69 |
<div class="row">
|
70 |
<div class="col s8">
|
71 |
-
<VegaLite {topic_overview_data} spec={topic_overview_spec} bind:view={topic_overview_view}/>
|
72 |
</div>
|
73 |
</div>
|
74 |
|
|
|
7 |
import Card, { Content } from '@smui/card';
|
8 |
|
9 |
export let data;
|
|
|
|
|
|
|
10 |
|
11 |
let show_step1_info = false;
|
12 |
|
|
|
65 |
{/if}
|
66 |
<div class="row">
|
67 |
<div class="col s8">
|
68 |
+
<VegaLite data={topic_overview_data} spec={topic_overview_spec} bind:view={topic_overview_view}/>
|
69 |
</div>
|
70 |
</div>
|
71 |
|
indie_label_svelte/src/SubmitReportDialog.svelte
CHANGED
@@ -2,20 +2,20 @@
|
|
2 |
import Dialog, { Title, Content, Actions } from "@smui/dialog";
|
3 |
import Button, { Label } from "@smui/button";
|
4 |
import Textfield from "@smui/textfield";
|
5 |
-
import Select, { Option } from "@smui/select";
|
6 |
import CircularProgress from '@smui/circular-progress';
|
|
|
7 |
|
8 |
export let open;
|
9 |
export let cur_user;
|
10 |
export let all_reports;
|
|
|
11 |
let email = "";
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
let sep_selection = "";
|
19 |
|
20 |
let promise_submit = Promise.resolve(null);
|
21 |
function handleSubmitReport() {
|
@@ -23,11 +23,19 @@
|
|
23 |
}
|
24 |
|
25 |
async function submitReport() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
let req_params = {
|
27 |
cur_user: cur_user,
|
28 |
-
reports: JSON.stringify(
|
|
|
29 |
email: email,
|
30 |
-
sep_selection: sep_selection,
|
31 |
};
|
32 |
|
33 |
let params = new URLSearchParams(req_params).toString();
|
@@ -51,20 +59,25 @@
|
|
51 |
<!-- Description -->
|
52 |
<div>
|
53 |
<b>When you are ready to send all of your audit reports to the <a href="https://avidml.org/" target="_blank">AI Vulnerability Database</a> (AVID), please fill out the following information.</b>
|
54 |
-
Only your submitted reports will be stored in the database for further analysis. While you can submit reports anonymously, we encourage you to provide your email so that we can contact you if we have any questions.
|
55 |
</div>
|
56 |
|
57 |
<!-- Summary of complete reports -->
|
58 |
<div>
|
59 |
-
<p><b>Summary of Reports to Send</b> (Reports that include
|
|
|
60 |
<ul>
|
61 |
-
{#each all_reports as report}
|
62 |
-
{#if report["
|
63 |
-
|
|
|
|
|
|
|
64 |
<ul>
|
65 |
<li>Error Type: {report["error_type"]}</li>
|
66 |
<li>Evidence: Includes {report["evidence"].length} example{(report["evidence"].length > 1) ? 's' : ''}</li>
|
67 |
<li>Summary/Suggestions: {report["text_entry"]}</li>
|
|
|
68 |
</ul>
|
69 |
{/if}
|
70 |
{/each}
|
@@ -73,11 +86,7 @@
|
|
73 |
|
74 |
<!-- Form fields -->
|
75 |
<div>
|
76 |
-
<
|
77 |
-
{#each all_sep_options as opt}
|
78 |
-
<Option value={opt}>{opt}</Option>
|
79 |
-
{/each}
|
80 |
-
</Select>
|
81 |
</div>
|
82 |
<div>
|
83 |
<Textfield bind:value={email} label="(Optional) Contact email" style="width: 90%" />
|
@@ -85,7 +94,7 @@
|
|
85 |
|
86 |
<!-- Submission and status message -->
|
87 |
<div class="dialog_footer">
|
88 |
-
<Button on:click={handleSubmitReport} variant="outlined">
|
89 |
<Label>Submit Report to AVID</Label>
|
90 |
</Button>
|
91 |
|
|
|
2 |
import Dialog, { Title, Content, Actions } from "@smui/dialog";
|
3 |
import Button, { Label } from "@smui/button";
|
4 |
import Textfield from "@smui/textfield";
|
|
|
5 |
import CircularProgress from '@smui/circular-progress';
|
6 |
+
import Checkbox from '@smui/checkbox';
|
7 |
|
8 |
export let open;
|
9 |
export let cur_user;
|
10 |
export let all_reports;
|
11 |
+
let name = "";
|
12 |
let email = "";
|
13 |
+
// which_reports_to_submit is an array of booleans that tracks whether the report
|
14 |
+
// in the corresponding index of all_reports should be submitted to AVID.
|
15 |
+
let which_reports_to_submit = [];
|
16 |
+
for (let i = 0; i < all_reports.length; i++) {
|
17 |
+
which_reports_to_submit.push(false);
|
18 |
+
}
|
|
|
19 |
|
20 |
let promise_submit = Promise.resolve(null);
|
21 |
function handleSubmitReport() {
|
|
|
23 |
}
|
24 |
|
25 |
async function submitReport() {
|
26 |
+
//Get the relevant reports
|
27 |
+
let submitted_reports = [];
|
28 |
+
for (let i = 0; i < which_reports_to_submit.length; i++) {
|
29 |
+
if (which_reports_to_submit[i]) {
|
30 |
+
submitted_reports.push(all_reports[i])
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
let req_params = {
|
35 |
cur_user: cur_user,
|
36 |
+
reports: JSON.stringify(submitted_reports),
|
37 |
+
name: name,
|
38 |
email: email,
|
|
|
39 |
};
|
40 |
|
41 |
let params = new URLSearchParams(req_params).toString();
|
|
|
59 |
<!-- Description -->
|
60 |
<div>
|
61 |
<b>When you are ready to send all of your audit reports to the <a href="https://avidml.org/" target="_blank">AI Vulnerability Database</a> (AVID), please fill out the following information.</b>
|
62 |
+
Only your submitted reports will be stored in the database for further analysis. While you can submit reports anonymously, we encourage you to provide your name and/or email so that we can contact you if we have any questions.
|
63 |
</div>
|
64 |
|
65 |
<!-- Summary of complete reports -->
|
66 |
<div>
|
67 |
+
<p><b>Summary of Reports Eligible to Send</b> (Reports that include all fields)</p>
|
68 |
+
<p> Select the reports you want to submit. </p>
|
69 |
<ul>
|
70 |
+
{#each all_reports as report, index}
|
71 |
+
{#if (report["evidence"].length > 0) && (report["text_entry"] != "") && (report["sep_selection"])}
|
72 |
+
|
73 |
+
<input type="checkbox" bind:checked={which_reports_to_submit[index]} />
|
74 |
+
|
75 |
+
<span>{report["title"]}</span>
|
76 |
<ul>
|
77 |
<li>Error Type: {report["error_type"]}</li>
|
78 |
<li>Evidence: Includes {report["evidence"].length} example{(report["evidence"].length > 1) ? 's' : ''}</li>
|
79 |
<li>Summary/Suggestions: {report["text_entry"]}</li>
|
80 |
+
<li>Audit Category: {report["sep_selection"] || ''}</li>
|
81 |
</ul>
|
82 |
{/if}
|
83 |
{/each}
|
|
|
86 |
|
87 |
<!-- Form fields -->
|
88 |
<div>
|
89 |
+
<Textfield bind:value={name} label="(Optional) Name" style="width: 90%" />
|
|
|
|
|
|
|
|
|
90 |
</div>
|
91 |
<div>
|
92 |
<Textfield bind:value={email} label="(Optional) Contact email" style="width: 90%" />
|
|
|
94 |
|
95 |
<!-- Submission and status message -->
|
96 |
<div class="dialog_footer">
|
97 |
+
<Button on:click={handleSubmitReport} variant="outlined" disabled={which_reports_to_submit.filter(item => item).length == 0}>
|
98 |
<Label>Submit Report to AVID</Label>
|
99 |
</Button>
|
100 |
|
server.py
CHANGED
@@ -426,6 +426,7 @@ def get_reports():
|
|
426 |
"error_type": "",
|
427 |
"evidence": [],
|
428 |
"text_entry": "",
|
|
|
429 |
"complete_status": False,
|
430 |
}
|
431 |
]
|
@@ -446,6 +447,7 @@ def get_fixed_scaffold():
|
|
446 |
"error_type": "System is under-sensitive",
|
447 |
"evidence": [],
|
448 |
"text_entry": "",
|
|
|
449 |
"complete_status": False,
|
450 |
},
|
451 |
{
|
@@ -453,6 +455,7 @@ def get_fixed_scaffold():
|
|
453 |
"error_type": "System is over-sensitive",
|
454 |
"evidence": [],
|
455 |
"text_entry": "",
|
|
|
456 |
"complete_status": False,
|
457 |
},
|
458 |
{
|
@@ -460,6 +463,7 @@ def get_fixed_scaffold():
|
|
460 |
"error_type": "System is under-sensitive",
|
461 |
"evidence": [],
|
462 |
"text_entry": "",
|
|
|
463 |
"complete_status": False,
|
464 |
},
|
465 |
{
|
@@ -467,6 +471,7 @@ def get_fixed_scaffold():
|
|
467 |
"error_type": "System is over-sensitive",
|
468 |
"evidence": [],
|
469 |
"text_entry": "",
|
|
|
470 |
"complete_status": False,
|
471 |
},
|
472 |
{
|
@@ -474,6 +479,7 @@ def get_fixed_scaffold():
|
|
474 |
"error_type": "System is under-sensitive",
|
475 |
"evidence": [],
|
476 |
"text_entry": "",
|
|
|
477 |
"complete_status": False,
|
478 |
},
|
479 |
]
|
@@ -484,6 +490,7 @@ def get_empty_report(title, error_type):
|
|
484 |
"error_type": error_type,
|
485 |
"evidence": [],
|
486 |
"text_entry": "",
|
|
|
487 |
"complete_status": False,
|
488 |
}
|
489 |
|
@@ -494,6 +501,7 @@ def get_tutorial_scaffold():
|
|
494 |
"error_type": "System is over-sensitive",
|
495 |
"evidence": [],
|
496 |
"text_entry": "",
|
|
|
497 |
"complete_status": False,
|
498 |
},
|
499 |
]
|
@@ -606,6 +614,7 @@ def get_prompts_scaffold():
|
|
606 |
"error_type": "System is over-sensitive",
|
607 |
"evidence": [],
|
608 |
"text_entry": "",
|
|
|
609 |
"complete_status": False,
|
610 |
},
|
611 |
{
|
@@ -613,6 +622,7 @@ def get_prompts_scaffold():
|
|
613 |
"error_type": "System is under-sensitive",
|
614 |
"evidence": [],
|
615 |
"text_entry": "",
|
|
|
616 |
"complete_status": False,
|
617 |
},
|
618 |
{
|
@@ -620,6 +630,7 @@ def get_prompts_scaffold():
|
|
620 |
"error_type": "",
|
621 |
"evidence": [],
|
622 |
"text_entry": "",
|
|
|
623 |
"complete_status": False,
|
624 |
},
|
625 |
{
|
@@ -627,6 +638,7 @@ def get_prompts_scaffold():
|
|
627 |
"error_type": "",
|
628 |
"evidence": [],
|
629 |
"text_entry": "",
|
|
|
630 |
"complete_status": False,
|
631 |
},
|
632 |
{
|
@@ -634,6 +646,7 @@ def get_prompts_scaffold():
|
|
634 |
"error_type": "",
|
635 |
"evidence": [],
|
636 |
"text_entry": "",
|
|
|
637 |
"complete_status": False,
|
638 |
},
|
639 |
]
|
@@ -648,7 +661,7 @@ def get_eligible_reports(reports):
|
|
648 |
|
649 |
# Submit all reports to AVID
|
650 |
# Logs the responses
|
651 |
-
def submit_reports_to_AVID(reports, cur_user,
|
652 |
# Set up the connection to AVID
|
653 |
root = os.environ.get('AVID_API_URL')
|
654 |
api_key = os.environ.get('AVID_API_KEY')
|
@@ -659,7 +672,8 @@ def submit_reports_to_AVID(reports, cur_user, email, sep_selection, debug=DEBUG)
|
|
659 |
print("Num eligible reports:", len(reports))
|
660 |
|
661 |
for r in reports:
|
662 |
-
|
|
|
663 |
url = root + "submit"
|
664 |
response = requests.post(url, json=json.loads(new_report), headers=key) # The loads ensures type compliance
|
665 |
uuid = response.json()
|
@@ -693,14 +707,14 @@ def save_reports(debug=DEBUG):
|
|
693 |
@app.route("/submit_avid_report")
|
694 |
def submit_avid_report():
|
695 |
cur_user = request.args.get("cur_user")
|
|
|
696 |
email = request.args.get("email")
|
697 |
-
sep_selection = request.args.get("sep_selection")
|
698 |
reports_json = request.args.get("reports")
|
699 |
|
700 |
reports = json.loads(reports_json)
|
701 |
|
702 |
# Submit reports to AVID
|
703 |
-
submit_reports_to_AVID(reports, cur_user,
|
704 |
|
705 |
results = {
|
706 |
"status": "success",
|
|
|
426 |
"error_type": "",
|
427 |
"evidence": [],
|
428 |
"text_entry": "",
|
429 |
+
"sep_selection": "",
|
430 |
"complete_status": False,
|
431 |
}
|
432 |
]
|
|
|
447 |
"error_type": "System is under-sensitive",
|
448 |
"evidence": [],
|
449 |
"text_entry": "",
|
450 |
+
"sep_selection": "",
|
451 |
"complete_status": False,
|
452 |
},
|
453 |
{
|
|
|
455 |
"error_type": "System is over-sensitive",
|
456 |
"evidence": [],
|
457 |
"text_entry": "",
|
458 |
+
"sep_selection": "",
|
459 |
"complete_status": False,
|
460 |
},
|
461 |
{
|
|
|
463 |
"error_type": "System is under-sensitive",
|
464 |
"evidence": [],
|
465 |
"text_entry": "",
|
466 |
+
"sep_selection": "",
|
467 |
"complete_status": False,
|
468 |
},
|
469 |
{
|
|
|
471 |
"error_type": "System is over-sensitive",
|
472 |
"evidence": [],
|
473 |
"text_entry": "",
|
474 |
+
"sep_selection": "",
|
475 |
"complete_status": False,
|
476 |
},
|
477 |
{
|
|
|
479 |
"error_type": "System is under-sensitive",
|
480 |
"evidence": [],
|
481 |
"text_entry": "",
|
482 |
+
"sep_selection": "",
|
483 |
"complete_status": False,
|
484 |
},
|
485 |
]
|
|
|
490 |
"error_type": error_type,
|
491 |
"evidence": [],
|
492 |
"text_entry": "",
|
493 |
+
"sep_selection": "",
|
494 |
"complete_status": False,
|
495 |
}
|
496 |
|
|
|
501 |
"error_type": "System is over-sensitive",
|
502 |
"evidence": [],
|
503 |
"text_entry": "",
|
504 |
+
"sep_selection": "",
|
505 |
"complete_status": False,
|
506 |
},
|
507 |
]
|
|
|
614 |
"error_type": "System is over-sensitive",
|
615 |
"evidence": [],
|
616 |
"text_entry": "",
|
617 |
+
"sep_selection": "",
|
618 |
"complete_status": False,
|
619 |
},
|
620 |
{
|
|
|
622 |
"error_type": "System is under-sensitive",
|
623 |
"evidence": [],
|
624 |
"text_entry": "",
|
625 |
+
"sep_selection": "",
|
626 |
"complete_status": False,
|
627 |
},
|
628 |
{
|
|
|
630 |
"error_type": "",
|
631 |
"evidence": [],
|
632 |
"text_entry": "",
|
633 |
+
"sep_selection": "",
|
634 |
"complete_status": False,
|
635 |
},
|
636 |
{
|
|
|
638 |
"error_type": "",
|
639 |
"evidence": [],
|
640 |
"text_entry": "",
|
641 |
+
"sep_selection": "",
|
642 |
"complete_status": False,
|
643 |
},
|
644 |
{
|
|
|
646 |
"error_type": "",
|
647 |
"evidence": [],
|
648 |
"text_entry": "",
|
649 |
+
"sep_selection": "",
|
650 |
"complete_status": False,
|
651 |
},
|
652 |
]
|
|
|
661 |
|
662 |
# Submit all reports to AVID
|
663 |
# Logs the responses
|
664 |
+
def submit_reports_to_AVID(reports, cur_user, name, email, debug=DEBUG):
|
665 |
# Set up the connection to AVID
|
666 |
root = os.environ.get('AVID_API_URL')
|
667 |
api_key = os.environ.get('AVID_API_KEY')
|
|
|
672 |
print("Num eligible reports:", len(reports))
|
673 |
|
674 |
for r in reports:
|
675 |
+
sep_selection = r["sep_selection"]
|
676 |
+
new_report = utils.convert_indie_label_json_to_avid_json(r, cur_user, name, email, sep_selection)
|
677 |
url = root + "submit"
|
678 |
response = requests.post(url, json=json.loads(new_report), headers=key) # The loads ensures type compliance
|
679 |
uuid = response.json()
|
|
|
707 |
@app.route("/submit_avid_report")
|
708 |
def submit_avid_report():
|
709 |
cur_user = request.args.get("cur_user")
|
710 |
+
name = request.args.get("name")
|
711 |
email = request.args.get("email")
|
|
|
712 |
reports_json = request.args.get("reports")
|
713 |
|
714 |
reports = json.loads(reports_json)
|
715 |
|
716 |
# Submit reports to AVID
|
717 |
+
submit_reports_to_AVID(reports, cur_user, name, email)
|
718 |
|
719 |
results = {
|
720 |
"status": "success",
|