feat: Rechtliche-Texte-Module auf 100% — Dead Code, RAG-Fallback, Fehler-UI
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 33s
CI / test-python-backend-compliance (push) Successful in 35s
CI / test-python-document-crawler (push) Successful in 24s
CI / test-python-dsms-gateway (push) Successful in 18s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 33s
CI / test-python-backend-compliance (push) Successful in 35s
CI / test-python-document-crawler (push) Successful in 24s
CI / test-python-dsms-gateway (push) Successful in 18s
Paket A: - einwilligungen/page.tsx: mockRecords (80 Zeilen toter Code) entfernt - consent/page.tsx: RAG-Suggest-Button im Create-Dialog (+handleRagSuggest) - workflow/page.tsx: uploadError State + rotes Fehler-Banner statt alert() Paket B: - cookie-banner/page.tsx: mockCategories → DEFAULT_COOKIE_CATEGORIES (Bug-Fix) DB-Kategorien haben jetzt immer Vorrang — kein Mock-Überschreiben mehr - test_einwilligungen_routes.py: +4 TestCookieBannerEmbedCode-Tests (36 gesamt) Paket C: - searchTemplates.ts: neue Hilfsdatei mit zwei-stufiger Suche 1. KLAUSUR_SERVICE (5s Timeout), 2. RAG-Fallback via ai-compliance-sdk - document-generator/page.tsx: ServiceMode State + UI-Badges (rag-only/offline) - searchTemplates.test.ts: 3 Vitest-Tests (KLAUSUR ok / RAG-Fallback / offline) flow-data.ts: alle 5 Rechtliche-Texte-Module auf completion: 100 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Template search helpers for document-generator.
|
||||
*
|
||||
* Provides a two-tier search:
|
||||
* 1. Primary: KLAUSUR_SERVICE (curated legal templates with full metadata)
|
||||
* 2. Fallback: RAG proxy (ai-compliance-sdk regulation search)
|
||||
*/
|
||||
|
||||
import type { LegalTemplateResult } from '@/lib/sdk/types'
|
||||
|
||||
export const KLAUSUR_SERVICE_URL =
|
||||
process.env.NEXT_PUBLIC_KLAUSUR_SERVICE_URL || 'http://localhost:8086'
|
||||
|
||||
export const RAG_PROXY = '/api/sdk/v1/rag'
|
||||
|
||||
export interface TemplateSearchParams {
|
||||
query: string
|
||||
templateType?: string
|
||||
licenseTypes?: string[]
|
||||
language?: 'de' | 'en'
|
||||
jurisdiction?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for legal templates with automatic RAG fallback.
|
||||
*
|
||||
* Tries KLAUSUR_SERVICE first (5 s timeout). If unavailable or returning an
|
||||
* error, falls back to the RAG proxy served by ai-compliance-sdk.
|
||||
* Returns an empty array if both services are down.
|
||||
*/
|
||||
export async function searchTemplates(
|
||||
params: TemplateSearchParams
|
||||
): Promise<LegalTemplateResult[]> {
|
||||
// 1. Primary: KLAUSUR_SERVICE
|
||||
try {
|
||||
const res = await fetch(`${KLAUSUR_SERVICE_URL}/api/v1/admin/templates/search`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
query: params.query,
|
||||
template_type: params.templateType,
|
||||
license_types: params.licenseTypes,
|
||||
language: params.language,
|
||||
jurisdiction: params.jurisdiction,
|
||||
limit: params.limit || 10,
|
||||
}),
|
||||
signal: AbortSignal.timeout(5000),
|
||||
})
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
return data.map((r: any) => ({
|
||||
id: r.id,
|
||||
score: r.score,
|
||||
text: r.text,
|
||||
documentTitle: r.document_title,
|
||||
templateType: r.template_type,
|
||||
clauseCategory: r.clause_category,
|
||||
language: r.language,
|
||||
jurisdiction: r.jurisdiction,
|
||||
licenseId: r.license_id,
|
||||
licenseName: r.license_name,
|
||||
licenseUrl: r.license_url,
|
||||
attributionRequired: r.attribution_required,
|
||||
attributionText: r.attribution_text,
|
||||
sourceName: r.source_name,
|
||||
sourceUrl: r.source_url,
|
||||
sourceRepo: r.source_repo,
|
||||
placeholders: r.placeholders || [],
|
||||
isCompleteDocument: r.is_complete_document,
|
||||
isModular: r.is_modular,
|
||||
requiresCustomization: r.requires_customization,
|
||||
outputAllowed: r.output_allowed ?? true,
|
||||
modificationAllowed: r.modification_allowed ?? true,
|
||||
distortionProhibited: r.distortion_prohibited ?? false,
|
||||
}))
|
||||
}
|
||||
} catch {
|
||||
// KLAUSUR_SERVICE not reachable — fall through to RAG
|
||||
}
|
||||
|
||||
// 2. Fallback: RAG proxy
|
||||
try {
|
||||
const res = await fetch(`${RAG_PROXY}/search`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ query: params.query || '', limit: params.limit || 10 }),
|
||||
})
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
return (data.results || []).map((r: any, i: number) => ({
|
||||
id: r.regulation_code || `rag-${i}`,
|
||||
score: r.score ?? 0.5,
|
||||
text: r.text || '',
|
||||
documentTitle: r.regulation_name || r.regulation_short || 'Dokument',
|
||||
templateType: 'regulation',
|
||||
clauseCategory: null,
|
||||
language: 'de',
|
||||
jurisdiction: 'eu',
|
||||
licenseId: null,
|
||||
licenseName: null,
|
||||
licenseUrl: null,
|
||||
attributionRequired: false,
|
||||
attributionText: null,
|
||||
sourceName: 'RAG',
|
||||
sourceUrl: null,
|
||||
sourceRepo: null,
|
||||
placeholders: [],
|
||||
isCompleteDocument: false,
|
||||
isModular: true,
|
||||
requiresCustomization: true,
|
||||
outputAllowed: true,
|
||||
modificationAllowed: true,
|
||||
distortionProhibited: false,
|
||||
source: 'rag' as const,
|
||||
}))
|
||||
}
|
||||
} catch {
|
||||
// both services failed
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export async function getTemplatesStatus(): Promise<any> {
|
||||
const response = await fetch(`${KLAUSUR_SERVICE_URL}/api/v1/admin/templates/status`, {
|
||||
signal: AbortSignal.timeout(5000),
|
||||
})
|
||||
if (!response.ok) return null
|
||||
return response.json()
|
||||
}
|
||||
|
||||
export async function getSources(): Promise<any[]> {
|
||||
const response = await fetch(`${KLAUSUR_SERVICE_URL}/api/v1/admin/templates/sources`, {
|
||||
signal: AbortSignal.timeout(5000),
|
||||
})
|
||||
if (!response.ok) return []
|
||||
const data = await response.json()
|
||||
return data.sources || []
|
||||
}
|
||||
Reference in New Issue
Block a user