f183678f35
Adds Nordic-pack regex patterns for: - DD.MM.YYYY / DD/MM/YYYY / YYYY-MM-DD - Year ranges (2011/2012, 2018-2019) - Month + year (Norwegian + English, with optional day) - Year preceded by temporal preposition (i 2015, fra 2019, rundt 2018) Also renames the entity toggle from "Dates of birth" to "Dates" (broader scope) in all four languages, and expands the LLM prompt so soft date references in free text are caught even when regex misses them. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
135 lines
12 KiB
PHP
135 lines
12 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
$toolName = 'redact';
|
|
$toolTitle = 'Redact sensitive details';
|
|
$toolKind = 'Redaction Assistant';
|
|
$toolBadge = 'deterministic first';
|
|
require_once __DIR__ . '/includes/layout.php';
|
|
?>
|
|
<form id="toolForm" class="tool-form">
|
|
|
|
<div class="lang-switcher" id="redactLangSwitcher" role="group" aria-label="UI language">
|
|
<button type="button" class="lang-btn is-active" data-lang="en">🇬🇧 EN</button>
|
|
<button type="button" class="lang-btn" data-lang="no">🇳🇴 NO</button>
|
|
<button type="button" class="lang-btn" data-lang="uk">🇺🇦 UK</button>
|
|
<button type="button" class="lang-btn" data-lang="pl">🇵🇱 PL</button>
|
|
</div>
|
|
|
|
<div class="control-row" id="redactEngineControl">
|
|
<span class="control-label" data-i18n="redactEngine">Engine</span>
|
|
<label><input type="radio" name="redactEngine" value="azure_mini" checked id="redactEngineAzureMini"> <span data-i18n="redactEngineAzureMini">Azure gpt-4o-mini</span> ★ <small class="control-hint">(fast)</small></label>
|
|
<label><input type="radio" name="redactEngine" value="azure_full" id="redactEngineAzureFull"> <span data-i18n="redactEngineAzureFull">Azure gpt-4o</span> <small class="control-hint">(best)</small></label>
|
|
<label><input type="radio" name="redactEngine" value="gpu" id="redactEngineGpu"> <span data-i18n="redactEngineGpu">GPU (cuttlefish)</span> <small class="control-hint">(local)</small></label>
|
|
<label><input type="radio" name="redactEngine" value="regex" id="redactEngineRegex"> <span data-i18n="redactEngineRegex">Regex only</span> <small class="control-hint">(free)</small></label>
|
|
</div>
|
|
<p class="upload-hint" data-i18n="redactEngineHint">Azure engines use your BNL Azure credits. GPU runs the local LiteLLM proxy. Regex-only is instant and free but finds no names or organisations.</p>
|
|
|
|
<details class="advanced-panel" id="redactAdvanced">
|
|
<summary class="advanced-toggle" data-i18n="redactAdvancedToggle">Advanced settings</summary>
|
|
|
|
<div class="control-row" id="redactModeControl">
|
|
<span class="control-label" data-i18n="redactMode">Mode</span>
|
|
<label><input type="radio" name="redactionMode" value="standard" checked> <span data-i18n="redactModeStandard">Standard</span></label>
|
|
<label><input type="radio" name="redactionMode" value="strict"> <span data-i18n="redactModeStrict">Strict</span></label>
|
|
</div>
|
|
<p class="upload-hint" data-i18n="redactModeHint">Standard: regex patterns + LLM scan for names/orgs/places. Strict: also replaces any capitalised two-word phrase as a potential name — more aggressive, may produce false positives.</p>
|
|
|
|
<div class="control-row" id="redactRegionControl">
|
|
<span class="control-label" data-i18n="redactRegion">Region</span>
|
|
<label><input type="radio" name="redactionRegion" value="nordic" checked> <span data-i18n="redactRegionNordic">Nordic</span></label>
|
|
<label><input type="radio" name="redactionRegion" value="european"> <span data-i18n="redactRegionEuropean">European</span></label>
|
|
<label><input type="radio" name="redactionRegion" value="echr"> <span data-i18n="redactRegionEchr">ECHR</span></label>
|
|
<label><input type="radio" name="redactionRegion" value="global"> <span data-i18n="redactRegionGlobal">Global</span></label>
|
|
</div>
|
|
<p class="upload-hint" data-i18n="redactRegionHint">Nordic: Norwegian fødselsnummer, phone, email, addresses. European: adds IBAN, SE personnummer, UK NI. ECHR: adds application numbers, DOB phrases. Global: adds US SSN, document numbers.</p>
|
|
|
|
<div class="control-row entity-toggles" id="redactEntityControl">
|
|
<span class="control-label" data-i18n="redactEntities">Redact</span>
|
|
<label><input type="checkbox" name="redactNames" id="redactNames" checked> <span data-i18n="redactEntityNames">Names</span></label>
|
|
<label><input type="checkbox" name="redactOrgs" id="redactOrgs" checked> <span data-i18n="redactEntityOrgs">Organisations</span></label>
|
|
<label><input type="checkbox" name="redactPlaces" id="redactPlaces" checked> <span data-i18n="redactEntityPlaces">Places</span></label>
|
|
<label><input type="checkbox" name="redactDob" id="redactDob" checked> <span data-i18n="redactEntityDob">Dates</span></label>
|
|
</div>
|
|
|
|
<div class="control-row" id="redactOfficialsControl">
|
|
<span class="control-label" data-i18n="redactOfficials">Officials</span>
|
|
<label><input type="checkbox" name="keepOfficials" id="keepOfficialsCheck"> <span data-i18n="redactKeepOfficials">Keep official names (judges, experts)</span></label>
|
|
</div>
|
|
<p class="upload-hint" data-i18n="redactOfficialsHint">When checked, judges, expert witnesses and caseworkers keep their names in a labelled tag: [JUDGE: Andersen]. Uncheck to replace all names with generic role tags.</p>
|
|
|
|
<div class="control-row" id="redactOutputControl">
|
|
<span class="control-label" data-i18n="redactOutput">Output</span>
|
|
<label><input type="radio" name="outputFormat" value="contextual" checked> <span data-i18n="redactOutputContextual">Contextual tags</span> ★ <small class="control-hint">[FATHER], [JUDGE: Name]</small></label>
|
|
<label><input type="radio" name="outputFormat" value="generic"> <span data-i18n="redactOutputGeneric">Generic tags</span> <small class="control-hint">[PERSON], [ORG]</small></label>
|
|
<label><input type="radio" name="outputFormat" value="pseudonym"> <span data-i18n="redactOutputPseudo">Pseudonyms</span> <small class="control-hint">Ola Nordmann, +47 400 00 001</small></label>
|
|
</div>
|
|
<p class="upload-hint" data-i18n="redactOutputHint">Contextual: each person gets a role tag so their identity is traceable within the document. Generic: all names become [PERSON]. Pseudonyms: replaced with plausible fake Norwegian values.</p>
|
|
|
|
<div class="exempt-section" id="exemptSection">
|
|
<div class="alias-header">
|
|
<span class="control-label" data-i18n="redactExempt">Exempt names</span>
|
|
<button type="button" id="addExemptRow" class="alias-add-btn">+ <span data-i18n="redactExemptAdd">Add</span></button>
|
|
</div>
|
|
<div id="exemptRows"></div>
|
|
<p class="alias-hint" data-i18n="redactExemptHint">Names listed here will never be redacted, even if the AI would otherwise remove them — e.g. a judge or expert who must remain identifiable.</p>
|
|
</div>
|
|
|
|
<div class="alias-section" id="aliasSection">
|
|
<div class="alias-header">
|
|
<span class="control-label" data-i18n="redactAliases">Name aliases</span>
|
|
<button type="button" id="addAliasRow" class="alias-add-btn">+ <span data-i18n="redactAliasAdd">Add</span></button>
|
|
</div>
|
|
<div id="aliasRows"></div>
|
|
<p class="alias-hint" data-i18n="redactAliasHint">Replace a specific name with a custom bracketed label, e.g. “David Jr” → [Junior].</p>
|
|
</div>
|
|
|
|
</details>
|
|
|
|
<div class="upload-zone" id="uploadZone" role="region" aria-label="File upload" data-i18n-aria="redactUploadAria">
|
|
<input type="file" id="uploadInput" multiple accept=".pdf,.docx,.txt" aria-label="Choose files">
|
|
<div id="uploadPrompt" class="upload-prompt">
|
|
<span class="upload-icon" aria-hidden="true">⇧</span>
|
|
<p><span data-i18n="redactUploadDrop">Drop up to 5 files here, or</span> <label for="uploadInput" class="upload-browse" data-i18n="redactUploadBrowse">browse</label></p>
|
|
<p class="upload-hint"><strong>PDF</strong>, <strong>DOCX</strong>, <strong>TXT</strong> — <span data-i18n="redactUploadHint">text extracted in memory, never stored</span></p>
|
|
</div>
|
|
<div id="uploadFileInfo" class="upload-file is-hidden">
|
|
<ul id="uploadFileList" class="upload-file-list"></ul>
|
|
<button type="button" id="uploadClear" class="upload-clear" data-i18n="redactUploadClear">× Clear</button>
|
|
</div>
|
|
</div>
|
|
|
|
<label class="input-label" for="toolInput" id="inputLabel" data-i18n="redactInputLabel">Pasted text</label>
|
|
<textarea id="toolInput" name="toolInput" rows="10" required data-i18n-placeholder="redactInputPlaceholder" placeholder="Paste text containing names, phone numbers, emails, addresses, or national ID numbers."></textarea>
|
|
|
|
<div class="form-footer">
|
|
<p id="toolStatus" class="form-status" role="status" aria-live="polite"></p>
|
|
<button id="runButton" type="submit" data-i18n="redactRun">Run</button>
|
|
</div>
|
|
</form>
|
|
|
|
<section id="results" class="results" aria-live="polite">
|
|
<div class="empty-state">
|
|
<h3 data-i18n="redactReadyTitle">Ready</h3>
|
|
<p data-i18n="redactReadyDesc">Paste text or upload a file, configure redaction options, then run.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Hidden stubs so tools.js element refs don't crash on this page -->
|
|
<div class="is-hidden" id="languageControl" aria-hidden="true"><input type="radio" name="language" value="en" checked></div>
|
|
<div class="is-hidden" id="redactionControl" aria-hidden="true"></div>
|
|
<div class="is-hidden" id="audioZone" aria-hidden="true">
|
|
<input type="file" id="audioInput" style="display:none">
|
|
<div id="audioPrompt"></div>
|
|
<div id="audioFileInfo"><ol id="audioQueueList"></ol><button type="button" id="audioClear"></button></div>
|
|
</div>
|
|
<div class="is-hidden" id="diarizeControl" aria-hidden="true">
|
|
<input type="checkbox" id="diarizeCheck">
|
|
<input type="number" id="numSpeakersInput">
|
|
</div>
|
|
<div class="is-hidden" id="transcribeLangControl" aria-hidden="true"><input type="radio" name="transcribeLang" value="no" checked></div>
|
|
<div class="is-hidden" id="vocabControl" aria-hidden="true">
|
|
<div id="vocabPresets"></div>
|
|
<textarea id="initPromptInput"></textarea>
|
|
</div>
|
|
<?php require_once __DIR__ . '/includes/layout_footer.php'; ?>
|