feat(rag): add QA Split-View Chunk-Browser for ingestion verification

New ChunkBrowserQA component replaces inline chunk browser with:
- Document sidebar with live chunk counts per regulation (batched Qdrant count API)
- Sequential chunk navigation with arrow keys (1/N through all chunks of a document)
- Overlap display showing previous/next chunk boundaries (amber-highlighted)
- Split-view with original PDF via iframe (estimated page from chunk index)
- Adjustable chunks-per-page ratio for PDF page estimation

Extracts REGULATIONS_IN_RAG and REGULATION_INFO to shared rag-constants.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-02-28 17:46:11 +01:00
parent 984dfab975
commit 8c42fefa77
6 changed files with 1377 additions and 355 deletions

View File

@@ -119,6 +119,32 @@ export async function GET(request: NextRequest) {
total_in_page: points.length,
})
}
case 'regulation-counts-batch': {
const col = searchParams.get('collection') || 'bp_compliance_gesetze'
const codes = (searchParams.get('codes') || '').split(',').filter(Boolean)
const results: Record<string, number> = {}
for (let i = 0; i < codes.length; i += 10) {
const batch = codes.slice(i, i + 10)
await Promise.all(batch.map(async (code) => {
try {
const res = await fetch(`${QDRANT_URL}/collections/${encodeURIComponent(col)}/points/count`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
filter: { must: [{ key: 'regulation_code', match: { value: code } }] },
exact: true,
}),
cache: 'no-store',
})
if (res.ok) {
const data = await res.json()
results[code] = data.result?.count || 0
}
} catch { /* skip failed counts */ }
}))
}
return NextResponse.json({ counts: results })
}
case 'collection-count': {
const col = searchParams.get('collection') || 'bp_compliance_gesetze'
const countRes = await fetch(`${QDRANT_URL}/collections/${encodeURIComponent(col)}`, {