Skip to content

Commit

Permalink
Voeg de mogelijkheid toe vereisten te filteren op labels uit de
Browse files Browse the repository at this point in the history
AI-Verordening door zelf labels te kiezen of de beslishulp te gebruiken.
  • Loading branch information
uittenbroekrobbert committed Feb 19, 2025
1 parent 0829eea commit bde7287
Show file tree
Hide file tree
Showing 52 changed files with 1,088 additions and 104 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ site


.Rproj.user
/tmp-site/
85 changes: 85 additions & 0 deletions docs/html/ai-verordening-popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<form class="form" id="ai-act-labels-form" onsubmit="getLabelsFromForm(this); filterTable(); return false;">

<h2>Bepaal je AI-verordening profiel</h2>
<p>
Vul de velden hieronder in om je AI-verordening profiel samen te stellen.<br/>
Op basis van deze informatie worden de relevante vereisten voor jouw AI-systeem gefilterd.
</p>

<div class="form__row">
<label class="form__label" id="rol-label">Rol</label>
<div class="input-checkbox">
<input type="checkbox" id="role-aanbieder" name="rol-ai-act" value="aanbieder" class="checkbox__input">
<label class="checkbox__label" for="role-aanbieder">Aanbieder</label>
</div>
<div class="input-checkbox">
<input type="checkbox" id="role-gebruiksverantwoordelijke" name="rol-ai-act" value="gebruiksverantwoordelijke" class="checkbox__input">
<label class="checkbox__label" for="role-gebruiksverantwoordelijke">Gebruiksverantwoordelijke</label>
</div>
<div class="input-checkbox">
<input type="checkbox" id="role-importeur" name="rol-ai-act" value="importeur" class="checkbox__input">
<label class="checkbox__label" for="role-importeur">Importeur</label>
</div>
<div class="input-checkbox">
<input type="checkbox" id="role-distributeur" name="rol-ai-act" value="distributeur" class="checkbox__input">
<label class="checkbox__label" for="role-distributeur">Distributeur</label>
</div>
</div>

<div class="form__row">
<label class="form__label" id="type-label" for="type">
Type AI toepassing
<span class="info-icon" title="Het is alleen mogelijk om het label 'impactvol' of 'geen-impactvol algoritme' te krijgen wanneer er geen sprake is van een AI-systeem of AI-model">i</span>
</label>
<select class="input-select" id="type" name="soort-toepassing" onchange="updateFieldsBasedOnType(this)">
<option value="" hidden="">Selecteer optie</option>
<option value="ai-systeem">AI-systeem</option>
<option value="ai-systeem-voor-algemene-doeleinden">AI-systeem voor algemene doeleinden</option>
<option value="ai-model-voor-algemene-doeleinden">AI-model voor algemene doeleinden</option>
<option value="impactvol-algoritme">Impactvol algoritme</option>
<option value="niet-impactvol-algoritme">Niet-impactvol algoritme</option>
</select>
</div>

<div class="form__row">
<label class="form__label" id="label-risk-group" for="risk-group">
In welke risicogroep valt de applicatie?
<span class="info-icon" title="Alleen van toepassing op AI-systeem en AI-systeem voor algemene doeleinden">i</span>
</label>
<select class="input-select" id="risk-group" name="risicogroep" disabled>
<option value="" hidden="">Selecteer optie</option>
<option value="hoog-risico-ai-systeem">Hoog-risico</option>
<option value="geen-hoog-risico-ai-systeem">Geen hoog-risico</option>
<option value="verboden-ai">Verboden AI</option>
<option value="uitzondering-van-toepassing">Uitzondering van toepassing</option>
</select>
</div>

<div class="form__row">
<label class="form__label" id="label-transparency-obligations" for="transparency-obligations">
Zijn er transparantieverplichtingen?
<span class="info-icon" title="Alleen van toepassing op AI-systeem en AI-systeem voor algemene doeleinden">i</span>
</label>
<select class="input-select" id="transparency-obligations" name="transparantieverplichting" disabled>
<option value="" hidden="">Selecteer optie</option>
<option value="transparantieverplichting">Transparantieverplichting</option>
<option value="geen-transparantieverplichting">Geen transparantieverplichting</option>
</select>
</div>

<div class="form__row">
<label class="form__label" id="label-systemic-risk" for="systemic-risk">
Is er sprake van een systeemrisico?
<span class="info-icon" title="Alleen van toepassing op AI-model voor algemene doeleinden">i</span>
</label>
<select class="input-select" id="systemic-risk" name="systeemrisico" disabled>
<option value="" hidden="">Selecteer optie</option>
<option value="systeemrisico">Systeemrisico</option>
<option value="geen-systeemrisico">Geen systeemrisico</option>
</select>
</div>

<div class="form__row">
<button class="button--primary" type="submit">Filter toepassen</button>
</div>
</form>
11 changes: 11 additions & 0 deletions docs/html/beslishulp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<html lang="nl">
<body>
<div id="app">
<script
data-showCloseOnEndMsg="Resultaten overnemen en afsluiten"
data-showCloseOnEnd="true"
data-fontPath="/Algoritmekader/assets/"
src="https://github.com/MinBZK/ai-verordening-beslishulp/releases/download/v.1.2.5/index.js"></script>
</div>
</body>
</html>
72 changes: 69 additions & 3 deletions docs/javascripts/filtering.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,30 @@ function filterTable() {
var table = document.getElementById("myTable");
var tr = table ? table.getElementsByTagName("tr") : [];

for (var i = 1; i < tr.length; i++) { // Skip header row
var labelsInput = document.getElementById("labelsInput").value.split(",").map(item => item.trim()).filter(item => item !== "");

var labelsToFilterOn = []
if (labelsInput.length > 0) {
labelsToFilterOn.push(...labelsInput);
// prefill all labels that are missing, the rule is:
for (const [_, labels] of labelMapper.groups) {
let foundLabelInGroup = labelsInput.some(label => labels.has(label));
if (!foundLabelInGroup) {
labelsToFilterOn.push(...labels);
}
}
}

for (let i = 1; i < tr.length; i++) { // Skip header row
var labelMatchConditions = ""
if (tr[i].hasAttribute("data-labels")) {
labelMatchConditions = tr[i].getAttribute("data-labels")
}
var uitzonderingMatchConditions = [];
if (tr[i].hasAttribute("data-uitzondering")) {
uitzonderingMatchConditions = tr[i].getAttribute("data-uitzondering").split(",").map(item => item.trim()).filter(item => item !== "");
}

var td = tr[i].getElementsByTagName("td")[1]; // Maatregelen column (td[0])
var roles = tr[i].getElementsByTagName("td")[2]; // Rollen column (td[1])
var lc = tr[i].getElementsByTagName("td")[3]; // Levenscyclus column (td[2])
Expand All @@ -153,14 +176,22 @@ function filterTable() {
var txtValue3 = lc.textContent || lc.innerText; // Levenscyclus value
var txtValue4 = onderwerpen.textContent || onderwerpen.innerText; // Onderwerpen value

console.log(`Row ${i} values: `, { txtValue, txtValue2, txtValue3, txtValue4 });
if (tr[i].getElementsByTagName("td")[2].querySelectorAll(".debug").length === 0) {
tr[i].getElementsByTagName("td")[2].innerHTML += "<div class='debug'></div>";
}

// Check if all selected filters are present
var roleMatch = selectedRoles.every(role => txtValue2.toUpperCase().indexOf(role) > -1);
var lcMatch = selectedLevenscyclus.every(lc => txtValue3.toUpperCase().indexOf(lc) > -1);
var onderwerpMatch = selectedOnderwerpen.every(onderwerp => txtValue4.toUpperCase().indexOf(onderwerp) > -1);
var labelMatch = labelMatchConditions === "" || labelsToFilterOn.length === 0 || evaluateLabelExpression(labelMatchConditions, labelsToFilterOn);
var uitzonderingMatch = anyExpressionMatches(uitzonderingMatchConditions, labelsInput);

if (txtValue.toUpperCase().indexOf(filter) > -1 && roleMatch && lcMatch && onderwerpMatch) {
if (uitzonderingMatch && labelMatch) {
labelMatch = false
}

if (txtValue.toUpperCase().indexOf(filter) > -1 && roleMatch && lcMatch && onderwerpMatch && labelMatch) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
Expand All @@ -170,4 +201,39 @@ function filterTable() {

// Trigger contentUpdated to reinitialize Choices.js after filtering
document.dispatchEvent(new Event('contentUpdated'));
}

/*
Given an expression like: ("ai-systeem-voor-algemene-doeleinden" || "ai-systeem") && "open-source" && "geen-transparantieverplichting" && "geen-hoog-risico-ai-systeem"
and an array of labels, evaluates the expression and returns true or false.
*/
function evaluateLabelExpression(expression, labels) {
if (expression === "" || labels.length === 0) {
return false;
}
// replace the string with function calls to hasLabel so we get true / false values
const transformedExpression = expression.replace(/["']?([a-zA-Z0-9-_]+)["']?/g, "hasLabel('$1')");

// create the function that executes our expression
const functionBody =
'const hasLabel = (label) => labels.includes(labelMapper.find(label).label);' +
'return ' + transformedExpression + ';';

try {
return new Function('labels', functionBody)(labels);
} catch (error) {
console.error('Error evaluating expression:', error);
return false;
}
}

/**
* Given a list of expressions and the current labels, returns true if any expression matches with the given labels, else false
* @param expressions a list of expressions, like:
* ["uitzondering-van-toepassing", ("ai-systeem-voor-algemene-doeleinden" || "ai-systeem") && "open-source" && "geen-transparantieverplichting" && "geen-hoog-risico-ai-systeem"]
* @param labels the labels the test against, like ["ai-systeem","uitzondering-van-toepassing"]
* @returns true if any expression matches with the given labels, else false
*/
function anyExpressionMatches(expressions, labels) {
return expressions.some(expression => evaluateLabelExpression(expression, labels));
}
Loading

0 comments on commit bde7287

Please sign in to comment.