d425c99e8e
New sixth tool in the hub. Accepts MP3/WAV/OGG/M4A/FLAC/WEBM up to 200 MB, proxies to Whisper on cuttlefish GPU. Optional speaker separation with LLM role labelling (dommer, advokat, forelder, sakkyndig, etc. via GPT-4o-mini). Client-side TXT / SRT / VTT download from segment data. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
320 lines
18 KiB
PHP
320 lines
18 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/includes/bootstrap.php';
|
|
$authenticated = dbnToolsIsAuthenticated();
|
|
?>
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Do Better Norge — AI Legal Research</title>
|
|
<meta name="description" content="AI-powered family law research for Norway. Source-cited answers from curated legal corpora, with a post-generation reviewer pass. Powered by CaveauAI.">
|
|
<meta name="robots" content="index, follow">
|
|
<link rel="canonical" href="https://ai.dobetternorge.no/">
|
|
<meta property="og:title" content="Do Better Norge — AI Legal Research">
|
|
<meta property="og:description" content="Source-cited answers from curated Norwegian law corpora. Every claim checked against real sources before it reaches you.">
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:url" content="https://ai.dobetternorge.no/">
|
|
<meta name="theme-color" content="#f7f8fb">
|
|
<link rel="stylesheet" href="assets/css/tools.css">
|
|
</head>
|
|
<body data-authenticated="<?= $authenticated ? 'true' : 'false' ?>">
|
|
<div id="publicLanding" class="showcase-page<?= $authenticated ? ' is-hidden' : '' ?>">
|
|
|
|
<header class="showcase-header">
|
|
<div class="showcase-header-inner">
|
|
<div class="showcase-brand">
|
|
<p class="eyebrow">Do Better Norge</p>
|
|
<h1 class="showcase-title">AI Legal Research</h1>
|
|
<p class="showcase-tagline">Source-cited answers from curated Norwegian law corpora</p>
|
|
<a href="https://caveauai.bluenotelogic.com/" class="powered-badge" rel="noopener" target="_blank">Powered by CaveauAI</a>
|
|
</div>
|
|
<a href="#access" class="cta-button">Access Legal Tools →</a>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="hiw-section">
|
|
<div class="section-inner">
|
|
<h2 class="section-heading">How it works</h2>
|
|
<p class="section-sub">From question to reviewed, cited answer in three steps</p>
|
|
<div class="hiw-steps">
|
|
<div class="hiw-step">
|
|
<div class="hiw-num">01</div>
|
|
<h3>Curated legal corpus</h3>
|
|
<p>Norwegian family law, ECHR rulings, and Lovdata sources are indexed, chunked, and embedded by CaveauAI’s ingestion pipeline.</p>
|
|
</div>
|
|
<div class="hiw-step">
|
|
<div class="hiw-num">02</div>
|
|
<h3>Hybrid retrieval</h3>
|
|
<p>Your question triggers vector similarity search and keyword retrieval — sources are scored, re-ranked, and presented as a labelled evidence trail.</p>
|
|
</div>
|
|
<div class="hiw-step">
|
|
<div class="hiw-num">03</div>
|
|
<h3>Reviewed, cited answer</h3>
|
|
<p>A post-generation reviewer checks every claim against retrieved sources before the answer reaches you. Citations are attached to real corpus documents.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="cap-section">
|
|
<div class="section-inner">
|
|
<h2 class="section-heading">Six tools, one suite</h2>
|
|
<div class="cap-grid">
|
|
<div class="cap-card">
|
|
<span class="cap-label">Ask</span>
|
|
<h3>Ask</h3>
|
|
<p>Source-grounded legal questions with citations and explicit uncertainty notes.</p>
|
|
</div>
|
|
<div class="cap-card">
|
|
<span class="cap-label">Search</span>
|
|
<h3>Search</h3>
|
|
<p>Retrieve up to seven relevant legal sources with titles, sections, and excerpts.</p>
|
|
</div>
|
|
<div class="cap-card">
|
|
<span class="cap-label">Summarize</span>
|
|
<h3>Summarize</h3>
|
|
<p>Extract facts, dates, parties, and legal references from pasted text.</p>
|
|
</div>
|
|
<div class="cap-card">
|
|
<span class="cap-label">Timeline</span>
|
|
<h3>Timeline</h3>
|
|
<p>Build a chronological event sequence from case notes or documents.</p>
|
|
</div>
|
|
<div class="cap-card">
|
|
<span class="cap-label">Redact</span>
|
|
<h3>Redact</h3>
|
|
<p>Remove sensitive personal data with configurable Nordic / ECHR / Global profiles.</p>
|
|
</div>
|
|
<div class="cap-card">
|
|
<span class="cap-label">Transcribe</span>
|
|
<h3>Transcribe</h3>
|
|
<p>Convert audio recordings to text with optional speaker separation and Norwegian role labelling.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="evidence-section">
|
|
<div class="section-inner evidence-inner">
|
|
<div class="evidence-copy">
|
|
<h2>Every answer shows its work</h2>
|
|
<p>Alongside each answer, the evidence trail shows which sources were retrieved, how they scored, which claims they support, and what remains uncertain. The legal reviewer pass checks all claims against the corpus before the answer is returned.</p>
|
|
<ul class="evidence-list">
|
|
<li>Source document, section, and authority type</li>
|
|
<li>Similarity score per retrieved chunk</li>
|
|
<li>Reviewer decision: approved / revised / insufficient support</li>
|
|
<li>Explicit uncertainty statement when the corpus can’t support a claim</li>
|
|
</ul>
|
|
</div>
|
|
<div class="evidence-mock" aria-hidden="true">
|
|
<p class="mock-label">Evidence Trail</p>
|
|
<div class="mock-step mock-done">
|
|
<span class="mock-dot"></span>
|
|
<div><strong>Query interpreted</strong><p>Barneloven §42 custody arrangements</p></div>
|
|
</div>
|
|
<div class="mock-step mock-done">
|
|
<span class="mock-dot"></span>
|
|
<div><strong>3 sources retrieved</strong><p>Barneloven, ECHR Johansen v. Norway, Ot.prp. nr. 56</p></div>
|
|
</div>
|
|
<div class="mock-step mock-done">
|
|
<span class="mock-dot"></span>
|
|
<div><strong>Reviewer: approved</strong><p>All claims supported by corpus sources</p></div>
|
|
</div>
|
|
<div class="mock-step">
|
|
<span class="mock-dot mock-dot--amber"></span>
|
|
<div><strong>Uncertainty noted</strong><p>Recent amendments after 2024 may not be indexed</p></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section id="access" class="access-section" aria-labelledby="accessTitle">
|
|
<div class="gate-panel">
|
|
<p class="eyebrow">Do Better Norge</p>
|
|
<h2 id="accessTitle">Access Legal Tools</h2>
|
|
<p class="gate-copy">Legal information and preparation support, not final legal advice.</p>
|
|
<form id="passcodeForm" class="passcode-form">
|
|
<label for="loginEmail">Email</label>
|
|
<input id="loginEmail" name="email" type="email" autocomplete="username email" required>
|
|
<label for="loginPassword">Password</label>
|
|
<div class="passcode-row">
|
|
<input id="loginPassword" name="password" type="password" autocomplete="current-password" required>
|
|
<button type="submit">Sign in</button>
|
|
</div>
|
|
<p id="gateStatus" class="form-status" role="status" aria-live="polite"></p>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
|
|
<footer class="showcase-footer">
|
|
<p>Do Better Norge · Built with <a href="https://caveauai.bluenotelogic.com/" rel="noopener" target="_blank">CaveauAI</a> by Blue Note Logic</p>
|
|
<p class="footer-disclaimer">Legal information and preparation support, not final legal advice. Not a substitute for professional legal counsel.</p>
|
|
</footer>
|
|
|
|
</div>
|
|
|
|
<main id="appShell" class="app-shell<?= $authenticated ? '' : ' is-hidden' ?>">
|
|
<header class="topbar">
|
|
<div>
|
|
<p class="eyebrow">Do Better Norge</p>
|
|
<h1>Legal Tools Hub</h1>
|
|
</div>
|
|
<div class="topbar-actions">
|
|
<span id="healthPill" class="status-pill">Session active</span>
|
|
<button id="healthButton" class="secondary-button" type="button">Health</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="disclaimer" role="note">
|
|
Legal information and preparation support, not final legal advice. Pasted text is processed in memory by default.
|
|
</div>
|
|
|
|
<section class="workspace" aria-label="Legal tools workspace">
|
|
<nav class="tool-rail" aria-label="Tools">
|
|
<button type="button" class="tool-tab is-active" data-tool="ask" aria-pressed="true">
|
|
<span>Ask</span>
|
|
<small>Source-grounded</small>
|
|
</button>
|
|
<button type="button" class="tool-tab" data-tool="search" aria-pressed="false">
|
|
<span>Search</span>
|
|
<small>Legal sources</small>
|
|
</button>
|
|
<button type="button" class="tool-tab" data-tool="summarize" aria-pressed="false">
|
|
<span>Summarize</span>
|
|
<small>Pasted text</small>
|
|
</button>
|
|
<button type="button" class="tool-tab" data-tool="timeline" aria-pressed="false">
|
|
<span>Timeline</span>
|
|
<small>Events</small>
|
|
</button>
|
|
<button type="button" class="tool-tab" data-tool="redact" aria-pressed="false">
|
|
<span>Redact</span>
|
|
<small>Privacy</small>
|
|
</button>
|
|
<button type="button" class="tool-tab" data-tool="transcribe" aria-pressed="false">
|
|
<span>Transcribe</span>
|
|
<small>Audio</small>
|
|
</button>
|
|
</nav>
|
|
|
|
<section class="tool-panel" aria-labelledby="toolTitle">
|
|
<div class="tool-heading">
|
|
<div>
|
|
<p id="toolKind" class="eyebrow">Source-grounded Legal Ask</p>
|
|
<h2 id="toolTitle">Ask a legal question</h2>
|
|
</div>
|
|
<span id="toolBadge" class="tool-badge">family-legal</span>
|
|
</div>
|
|
|
|
<form id="toolForm" class="tool-form">
|
|
<div class="control-row" id="languageControl">
|
|
<span class="control-label">Language</span>
|
|
<label><input type="radio" name="language" value="en" checked> English</label>
|
|
<label><input type="radio" name="language" value="no"> Norsk</label>
|
|
</div>
|
|
|
|
<div class="control-row is-hidden" id="transcribeLangControl">
|
|
<span class="control-label">Language</span>
|
|
<label><input type="radio" name="transcribeLang" value="auto" checked> Auto-detect</label>
|
|
<label><input type="radio" name="transcribeLang" value="no"> Norsk</label>
|
|
<label><input type="radio" name="transcribeLang" value="en"> English</label>
|
|
</div>
|
|
|
|
<div class="control-row is-hidden" id="diarizeControl">
|
|
<span class="control-label">Speakers</span>
|
|
<label><input type="checkbox" id="diarizeCheck" name="diarize"> Separate speakers</label>
|
|
<span class="control-label" style="margin-left:1.25rem">Count</span>
|
|
<input type="number" id="numSpeakersInput" name="num_speakers" min="2" max="10" placeholder="auto" class="num-speakers-input" aria-label="Expected speaker count">
|
|
</div>
|
|
|
|
<div class="control-row is-hidden" id="redactionControl">
|
|
<span class="control-label">Mode</span>
|
|
<label><input type="radio" name="redactionMode" value="standard" checked> Standard</label>
|
|
<label><input type="radio" name="redactionMode" value="strict"> Strict</label>
|
|
<span class="control-label" style="margin-left:1.25rem">Region</span>
|
|
<label><input type="radio" name="redactionRegion" value="nordic" checked> Nordic</label>
|
|
<label><input type="radio" name="redactionRegion" value="european"> European</label>
|
|
<label><input type="radio" name="redactionRegion" value="echr"> ECHR</label>
|
|
<label><input type="radio" name="redactionRegion" value="global"> Global</label>
|
|
</div>
|
|
|
|
<div class="upload-zone is-hidden" id="audioZone" role="region" aria-label="Audio upload">
|
|
<input type="file" id="audioInput" accept="audio/*,video/mp4,video/webm" aria-label="Choose audio file">
|
|
<div id="audioPrompt" class="upload-prompt">
|
|
<span class="upload-icon" aria-hidden="true">▶</span>
|
|
<p>Drop audio file here, or <label for="audioInput" class="upload-browse">browse</label></p>
|
|
<p class="upload-hint"><strong>MP3</strong>, <strong>WAV</strong>, <strong>OGG</strong>, <strong>M4A</strong>, <strong>FLAC</strong>, <strong>WEBM</strong> — max 200 MB</p>
|
|
</div>
|
|
<div id="audioFileInfo" class="upload-file is-hidden">
|
|
<ul class="upload-file-list"><li id="audioFileLine"><span id="audioFileName" class="upload-filename"></span><span id="audioFileSize" class="upload-chars"></span></li></ul>
|
|
<button type="button" id="audioClear" class="upload-clear" aria-label="Clear audio file">×</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="upload-zone is-hidden" id="uploadZone" role="region" aria-label="File upload">
|
|
<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>Drop up to 5 files (<strong>.pdf</strong>, <strong>.docx</strong>, <strong>.txt</strong>), or <label for="uploadInput" class="upload-browse">browse</label></p>
|
|
<p class="upload-hint">Text is extracted in memory and never stored.</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" aria-label="Clear uploaded files">×</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alias-section is-hidden" id="aliasSection">
|
|
<div class="alias-header">
|
|
<span class="control-label">Name aliases</span>
|
|
<button type="button" id="addAliasRow" class="alias-add-btn">+ Add</button>
|
|
</div>
|
|
<div id="aliasRows"></div>
|
|
<p class="alias-hint">Replace a name with a bracketed alias, e.g. “David Jr” → [Junior]</p>
|
|
</div>
|
|
|
|
<label class="input-label" for="toolInput" id="inputLabel">Question</label>
|
|
<textarea id="toolInput" name="toolInput" rows="10" required></textarea>
|
|
|
|
<div class="form-footer">
|
|
<p id="toolStatus" class="form-status" role="status" aria-live="polite"></p>
|
|
<button id="runButton" type="submit">Run Tool</button>
|
|
</div>
|
|
</form>
|
|
|
|
<section id="results" class="results" aria-live="polite">
|
|
<div class="empty-state">
|
|
<h3>Ready</h3>
|
|
<p>Choose a tool, run a request, and the answer will show the evidence trail beside it.</p>
|
|
</div>
|
|
</section>
|
|
</section>
|
|
|
|
<aside class="reasoning-panel" aria-labelledby="reasoningTitle">
|
|
<div class="reasoning-head">
|
|
<p class="eyebrow">Evidence trail</p>
|
|
<h2 id="reasoningTitle">Reasoning</h2>
|
|
</div>
|
|
<ol id="traceList" class="trace-list">
|
|
<li>
|
|
<span class="trace-status waiting"></span>
|
|
<div>
|
|
<strong>Waiting</strong>
|
|
<p>Run a tool to see interpretation, retrieval, confidence, uncertainty, and next step.</p>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
</aside>
|
|
</section>
|
|
</main>
|
|
|
|
<script>
|
|
window.DBN_TOOLS_AUTHENTICATED = <?= $authenticated ? 'true' : 'false' ?>;
|
|
</script>
|
|
<script src="assets/js/tools.js" defer></script>
|
|
</body>
|
|
</html>
|