Extract components and hooks from oversized page files (563/561/520 LOC) into colocated _components/ and _hooks/ subdirectories. All three page.tsx files are now thin orchestrators under 300 LOC each (dsfa: 216, audit-llm: 121, quality: 163). Zero behavior changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useCallback } from 'react'
|
|
import { API_BASE, getDateRange, type LLMLogEntry, type UsageStats, type ComplianceReport } from '../_components/types'
|
|
|
|
export function useAuditData(period: string, logFilter: { model: string; pii: string }) {
|
|
const [logEntries, setLogEntries] = useState<LLMLogEntry[]>([])
|
|
const [usageStats, setUsageStats] = useState<UsageStats | null>(null)
|
|
const [complianceReport, setComplianceReport] = useState<ComplianceReport | null>(null)
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
const loadLLMLog = useCallback(async () => {
|
|
setLoading(true)
|
|
setError(null)
|
|
try {
|
|
const { from, to } = getDateRange(period)
|
|
const params = new URLSearchParams({ from, to, limit: '100' })
|
|
if (logFilter.model) params.set('model', logFilter.model)
|
|
if (logFilter.pii === 'true') params.set('pii_detected', 'true')
|
|
if (logFilter.pii === 'false') params.set('pii_detected', 'false')
|
|
|
|
const res = await fetch(`${API_BASE}/llm?${params}`)
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
const data = await res.json()
|
|
setLogEntries(Array.isArray(data) ? data : data.entries || data.logs || [])
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : 'Fehler beim Laden')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}, [period, logFilter])
|
|
|
|
const loadUsage = useCallback(async () => {
|
|
setLoading(true)
|
|
setError(null)
|
|
try {
|
|
const { from, to } = getDateRange(period)
|
|
const res = await fetch(`${API_BASE}/usage?from=${from}&to=${to}`)
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
const data = await res.json()
|
|
setUsageStats(data)
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : 'Fehler beim Laden')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}, [period])
|
|
|
|
const loadCompliance = useCallback(async () => {
|
|
setLoading(true)
|
|
setError(null)
|
|
try {
|
|
const { from, to } = getDateRange(period)
|
|
const res = await fetch(`${API_BASE}/compliance-report?from=${from}&to=${to}`)
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
const data = await res.json()
|
|
setComplianceReport(data)
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : 'Fehler beim Laden')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}, [period])
|
|
|
|
const handleExport = useCallback(async (type: 'llm' | 'general' | 'compliance', format: 'json' | 'csv') => {
|
|
try {
|
|
const { from, to } = getDateRange(period)
|
|
const res = await fetch(`${API_BASE}/export/${type}?from=${from}&to=${to}&format=${format}`)
|
|
if (!res.ok) throw new Error(`Export fehlgeschlagen: ${res.status}`)
|
|
const blob = await res.blob()
|
|
const url = URL.createObjectURL(blob)
|
|
const a = document.createElement('a')
|
|
a.href = url
|
|
a.download = `audit-${type}-${from}-${to}.${format}`
|
|
a.click()
|
|
URL.revokeObjectURL(url)
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : 'Export fehlgeschlagen')
|
|
}
|
|
}, [period])
|
|
|
|
return {
|
|
logEntries,
|
|
usageStats,
|
|
complianceReport,
|
|
loading,
|
|
error,
|
|
loadLLMLog,
|
|
loadUsage,
|
|
loadCompliance,
|
|
handleExport,
|
|
}
|
|
}
|