Remove duplicate compliance and DSGVO admin pages that have been superseded by the unified SDK pipeline. Update navigation, sidebar, roles, and module registry to reflect the new structure. Add DSFA corpus API proxy and source-policy components. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
181 lines
5.7 KiB
TypeScript
181 lines
5.7 KiB
TypeScript
/**
|
|
* Legal Corpus API Proxy
|
|
*
|
|
* Proxies requests to klausur-service for RAG operations.
|
|
* This allows the client-side RAG page to call the API without CORS issues.
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server'
|
|
|
|
const KLAUSUR_SERVICE_URL = process.env.KLAUSUR_SERVICE_URL || 'http://klausur-service:8086'
|
|
const QDRANT_URL = process.env.QDRANT_URL || 'http://qdrant:6333'
|
|
|
|
export async function GET(request: NextRequest) {
|
|
const { searchParams } = new URL(request.url)
|
|
const action = searchParams.get('action')
|
|
|
|
try {
|
|
let url = `${KLAUSUR_SERVICE_URL}/api/v1/admin/legal-corpus`
|
|
|
|
switch (action) {
|
|
case 'status': {
|
|
// Query Qdrant directly for collection stats
|
|
const qdrantRes = await fetch(`${QDRANT_URL}/collections/bp_legal_corpus`, {
|
|
cache: 'no-store',
|
|
})
|
|
if (!qdrantRes.ok) {
|
|
return NextResponse.json({ error: 'Qdrant not available' }, { status: 503 })
|
|
}
|
|
const qdrantData = await qdrantRes.json()
|
|
const result = qdrantData.result || {}
|
|
return NextResponse.json({
|
|
collection: 'bp_legal_corpus',
|
|
totalPoints: result.points_count || 0,
|
|
vectorSize: result.config?.params?.vectors?.size || 0,
|
|
status: result.status || 'unknown',
|
|
regulations: {},
|
|
})
|
|
}
|
|
case 'search':
|
|
const query = searchParams.get('query')
|
|
const topK = searchParams.get('top_k') || '5'
|
|
const regulations = searchParams.get('regulations')
|
|
url += `/search?query=${encodeURIComponent(query || '')}&top_k=${topK}`
|
|
if (regulations) {
|
|
url += `®ulations=${encodeURIComponent(regulations)}`
|
|
}
|
|
break
|
|
case 'ingestion-status':
|
|
url += '/ingestion-status'
|
|
break
|
|
case 'regulations':
|
|
url += '/regulations'
|
|
break
|
|
case 'custom-documents':
|
|
url += '/custom-documents'
|
|
break
|
|
case 'pipeline-checkpoints':
|
|
url = `${KLAUSUR_SERVICE_URL}/api/v1/admin/pipeline/checkpoints`
|
|
break
|
|
case 'pipeline-status':
|
|
url = `${KLAUSUR_SERVICE_URL}/api/v1/admin/pipeline/status`
|
|
break
|
|
case 'traceability': {
|
|
const chunkId = searchParams.get('chunk_id')
|
|
const regulation = searchParams.get('regulation')
|
|
url += `/traceability?chunk_id=${encodeURIComponent(chunkId || '')}®ulation=${encodeURIComponent(regulation || '')}`
|
|
break
|
|
}
|
|
default:
|
|
return NextResponse.json({ error: 'Unknown action' }, { status: 400 })
|
|
}
|
|
|
|
const res = await fetch(url, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
cache: 'no-store',
|
|
})
|
|
|
|
const data = await res.json()
|
|
return NextResponse.json(data, { status: res.status })
|
|
} catch (error) {
|
|
console.error('Legal corpus proxy error:', error)
|
|
return NextResponse.json(
|
|
{ error: 'Failed to connect to klausur-service' },
|
|
{ status: 503 }
|
|
)
|
|
}
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
const { searchParams } = new URL(request.url)
|
|
const action = searchParams.get('action')
|
|
|
|
try {
|
|
let url = `${KLAUSUR_SERVICE_URL}/api/v1/admin/legal-corpus`
|
|
|
|
switch (action) {
|
|
case 'ingest': {
|
|
url += '/ingest'
|
|
const body = await request.json()
|
|
const res = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
const data = await res.json()
|
|
return NextResponse.json(data, { status: res.status })
|
|
}
|
|
|
|
case 'add-link': {
|
|
url += '/add-link'
|
|
const body = await request.json()
|
|
const res = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
const data = await res.json()
|
|
return NextResponse.json(data, { status: res.status })
|
|
}
|
|
|
|
case 'upload': {
|
|
url += '/upload'
|
|
// Forward FormData directly
|
|
const formData = await request.formData()
|
|
const res = await fetch(url, {
|
|
method: 'POST',
|
|
body: formData,
|
|
})
|
|
const data = await res.json()
|
|
return NextResponse.json(data, { status: res.status })
|
|
}
|
|
|
|
case 'start-pipeline': {
|
|
url = `${KLAUSUR_SERVICE_URL}/api/v1/admin/pipeline/start`
|
|
const body = await request.json()
|
|
const res = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
const data = await res.json()
|
|
return NextResponse.json(data, { status: res.status })
|
|
}
|
|
|
|
default:
|
|
return NextResponse.json({ error: 'Unknown action' }, { status: 400 })
|
|
}
|
|
} catch (error) {
|
|
console.error('Legal corpus proxy error:', error)
|
|
return NextResponse.json(
|
|
{ error: 'Failed to connect to klausur-service' },
|
|
{ status: 503 }
|
|
)
|
|
}
|
|
}
|
|
|
|
export async function DELETE(request: NextRequest) {
|
|
const { searchParams } = new URL(request.url)
|
|
const action = searchParams.get('action')
|
|
const docId = searchParams.get('docId')
|
|
|
|
try {
|
|
if (action === 'delete-document' && docId) {
|
|
const url = `${KLAUSUR_SERVICE_URL}/api/v1/admin/legal-corpus/custom-documents/${docId}`
|
|
const res = await fetch(url, { method: 'DELETE' })
|
|
const data = await res.json()
|
|
return NextResponse.json(data, { status: res.status })
|
|
}
|
|
|
|
return NextResponse.json({ error: 'Unknown action' }, { status: 400 })
|
|
} catch (error) {
|
|
console.error('Legal corpus proxy error:', error)
|
|
return NextResponse.json(
|
|
{ error: 'Failed to connect to klausur-service' },
|
|
{ status: 503 }
|
|
)
|
|
}
|
|
}
|