Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Beslishulp integreren bij vereisten #610

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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