Add Legal Analysis tool — two-pass DBN-legal pipeline

Restores the dbn-legal-agent-v3 fine-tune on ocelot (was silently aliased
to plain qwen2.5:14b in LiteLLM since the viper retirement) and ships a
new tool that uses it via a two-pass flow:

  Pass 1 (Azure 4o-mini)  → extract up to 5 distinct legal issues
  Pass 2 (ocelot v3 only) → answer each issue, ≤350 tokens, with corpus
  Pass 3 (Azure 4o-mini)  → synthesise overall assessment + next steps

The 12GB-VRAM constraint motivates the split: dbn-legal-agent-v3 stays
hot in VRAM through the 5 sequential per-issue calls because issue
extraction and synthesis run on Azure, not on ocelot.

New surface:
  - includes/LegalAnalysisAgent.php
  - api/legal-analysis.php           (NDJSON streaming endpoint)
  - legal-analysis.php               (dedicated tool page)
  - assets/js/legal-analysis.js      (streamed UI with per-issue cards)
  - Save-result + case-result.php rendering for legal-analysis output
  - Nav registration in all four UI languages

Add-on integration: a "⚖️🇳🇴 Run deep legal analysis on this text"
button now appears on Summarize, Ask, and Redact result pages and
streams the same pipeline inline below the existing result.

Existing tools relabelled: the misleading "🇳🇴 Norwegian specialist v3 "
option on advocate/deep-research/discrepancy/barnevernet is now honestly
"DBN Legal Agent" — now that the real fine-tune is actually deployed,
the label finally matches reality. The advocate.php v2 option was
removed since the v2 GGUF is retired.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 04:21:01 +02:00
parent 2013648ee0
commit 7e6463ed22
14 changed files with 1361 additions and 25 deletions
+130
View File
@@ -9267,3 +9267,133 @@ body.lt-landing {
font-size: 0.82rem;
width: 100%;
}
/* ── Legal Analysis tool ─────────────────────────────────────────────────── */
.la-pipeline {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1.2rem;
padding: 0.6rem 0.75rem;
background: #f5f7fb;
border-radius: 8px;
border: 1px solid #e2e7ef;
font-size: 0.85rem;
}
.la-step {
padding: 0.3rem 0.7rem;
border-radius: 5px;
background: #fff;
border: 1px solid #d8dde7;
}
.la-step.running {
border-color: #f59e0b;
background: #fffbeb;
animation: la-pulse 1.4s ease-in-out infinite;
}
.la-step.done {
border-color: #16a34a;
background: #f0fdf4;
color: #15803d;
}
@keyframes la-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.55; } }
.la-issues {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 1rem;
}
.la-issue {
border: 1px solid #d8dde7;
border-radius: 8px;
padding: 0.9rem 1rem;
background: #fff;
transition: border-color 0.2s, box-shadow 0.2s;
}
.la-issue.pending { opacity: 0.7; border-style: dashed; }
.la-issue.running {
border-color: #f59e0b;
box-shadow: 0 0 0 2px rgba(245,158,11,0.15);
}
.la-issue.answered {
border-color: #cbd5e1;
}
.la-issue__head {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.4rem;
}
.la-issue__num {
display: inline-block;
min-width: 1.8rem;
font-weight: 700;
color: #64748b;
font-size: 0.85rem;
}
.la-severity {
display: inline-block;
padding: 0.15rem 0.5rem;
border-radius: 999px;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.04em;
}
.la-severity-high { background: #fee2e2; color: #b91c1c; }
.la-severity-medium { background: #fef3c7; color: #92400e; }
.la-severity-low { background: #dcfce7; color: #166534; }
.la-issue__q {
margin: 0.2rem 0 0.4rem;
font-size: 1.02rem;
color: #1e293b;
}
.la-issue__ctx {
margin: 0 0 0.5rem;
font-size: 0.85rem;
color: #64748b;
}
.la-issue__status {
font-size: 0.85rem;
color: #f59e0b;
font-style: italic;
}
.la-issue__answer {
margin-top: 0.6rem;
padding-top: 0.6rem;
border-top: 1px solid #eef2f7;
}
.la-issue__answer h5 {
margin: 0 0 0.4rem;
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: #64748b;
}
.la-issue__answer p { margin: 0; line-height: 1.55; color: #1e293b; }
.la-issue__basis {
margin-top: 0.5rem;
font-size: 0.85rem;
color: #475569;
background: #f8fafc;
padding: 0.3rem 0.55rem;
border-radius: 5px;
display: inline-block;
}
.la-issue__check {
margin: 0.55rem 0 0;
font-size: 0.8rem;
color: #94a3b8;
}
.la-synthesis {
margin-bottom: 1.4rem;
padding: 1rem 1.2rem;
border-left: 4px solid var(--dbn-teal, #0f766e);
background: #ecfeff;
border-radius: 6px;
}
.la-synthesis h3 { margin-top: 0; color: #0e7490; }
.la-synthesis h4 { margin: 0.9rem 0 0.4rem; font-size: 0.95rem; color: #155e75; }