Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 42s
CI / test-go-edu-search (push) Successful in 34s
CI / test-python-klausur (push) Failing after 2m51s
CI / test-python-agent-core (push) Successful in 21s
CI / test-nodejs-website (push) Successful in 29s
sed replacement left orphaned hostname references in story page and empty lines in getApiBase functions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
162 lines
5.9 KiB
TypeScript
162 lines
5.9 KiB
TypeScript
'use client'
|
|
|
|
import { AIModuleSidebarResponsive } from '@/components/ai/AIModuleSidebar'
|
|
import { PagePurpose } from '@/components/common/PagePurpose'
|
|
import { TABS } from './types'
|
|
import { useMagicHelp } from './useMagicHelp'
|
|
import {
|
|
GlobalDragOverlay,
|
|
KeyboardShortcutsModal,
|
|
TabOverview,
|
|
TabTest,
|
|
TabBatch,
|
|
TabTraining,
|
|
TabArchitecture,
|
|
TabSettings,
|
|
} from './_components'
|
|
|
|
export default function MagicHelpPage() {
|
|
const h = useMagicHelp()
|
|
|
|
const getStatusBadge = () => {
|
|
if (!h.status) return null
|
|
switch (h.status.status) {
|
|
case 'available':
|
|
return <span className="px-3 py-1 text-xs font-medium rounded-full bg-green-100 text-green-700">Verfuegbar</span>
|
|
case 'not_installed':
|
|
return <span className="px-3 py-1 text-xs font-medium rounded-full bg-red-100 text-red-700">Nicht installiert</span>
|
|
case 'error':
|
|
return <span className="px-3 py-1 text-xs font-medium rounded-full bg-yellow-100 text-yellow-700">Fehler</span>
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6 relative">
|
|
<GlobalDragOverlay active={h.globalDragActive} />
|
|
<KeyboardShortcutsModal open={h.showShortcutHint} onClose={() => h.setShowShortcutHint(false)} />
|
|
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-slate-900 flex items-center gap-2">
|
|
<span className="text-2xl">✨</span>
|
|
Magic Help - Handschrifterkennung
|
|
</h1>
|
|
<p className="text-slate-500 mt-1">
|
|
KI-gestuetzte Klausurkorrektur mit TrOCR und Privacy-by-Design
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<button
|
|
onClick={() => h.setShowShortcutHint(true)}
|
|
className="p-2 text-slate-400 hover:text-slate-600 transition-colors"
|
|
title="Tastenkuerzel anzeigen (?)"
|
|
>
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
|
</svg>
|
|
</button>
|
|
{getStatusBadge()}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Page Purpose */}
|
|
<PagePurpose
|
|
title="Magic Help"
|
|
purpose="Testen und verbessern Sie die TrOCR-Handschrifterkennung. Laden Sie Bilder hoch, um die OCR-Qualitaet zu pruefen, und trainieren Sie das Modell mit LoRA Fine-Tuning. Teil der KI-Daten-Pipeline: Exportieren Sie Trainingsdaten zu OCR-Labeling oder importieren Sie Ground Truth fuer Fine-Tuning."
|
|
audience={['Entwickler', 'Administratoren', 'QA-Team']}
|
|
architecture={{
|
|
services: ['klausur-service (Python)', 'TrOCR (PyTorch)'],
|
|
databases: ['Modell-Cache', 'LoRA-Adapter'],
|
|
}}
|
|
relatedPages={[
|
|
{ name: 'OCR-Labeling', href: '/ai/ocr-labeling', description: 'Ground Truth erstellen' },
|
|
{ name: 'RAG Pipeline', href: '/ai/rag-pipeline', description: 'Erkannte Texte indexieren' },
|
|
]}
|
|
collapsible={true}
|
|
defaultCollapsed={true}
|
|
/>
|
|
|
|
<AIModuleSidebarResponsive currentModule="magic-help" />
|
|
|
|
{/* Quick paste hint */}
|
|
<div className="bg-gradient-to-r from-purple-50 to-blue-50 border border-purple-200 rounded-lg px-4 py-2 flex items-center gap-3 text-sm">
|
|
<span className="text-purple-600">💡</span>
|
|
<span className="text-slate-600">
|
|
<strong>Tipp:</strong> Druecke <kbd className="px-1.5 py-0.5 bg-white rounded border text-xs font-mono">Ctrl+V</kbd> um ein Bild aus der Zwischenablage einzufuegen, oder ziehe es einfach irgendwo ins Fenster.
|
|
</span>
|
|
</div>
|
|
|
|
{/* Tabs */}
|
|
<div className="flex gap-2 border-b border-slate-200 pb-2">
|
|
{TABS.map((tab) => (
|
|
<button
|
|
key={tab.id}
|
|
onClick={() => h.setActiveTab(tab.id)}
|
|
className={`px-4 py-2 rounded-t-lg text-sm font-medium transition-colors ${
|
|
h.activeTab === tab.id
|
|
? 'bg-purple-600 text-white'
|
|
: 'text-slate-600 hover:text-slate-900 hover:bg-slate-100'
|
|
}`}
|
|
title={tab.shortcut}
|
|
>
|
|
<span className="mr-2">{tab.icon}</span>
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Tab Content */}
|
|
{h.activeTab === 'overview' && (
|
|
<TabOverview status={h.status} loading={h.loading} onRefresh={h.fetchStatus} />
|
|
)}
|
|
|
|
{h.activeTab === 'test' && (
|
|
<TabTest
|
|
ocrResult={h.ocrResult}
|
|
ocrLoading={h.ocrLoading}
|
|
imagePreview={h.imagePreview}
|
|
uploadedImage={h.uploadedImage}
|
|
settings={h.settings}
|
|
showHeatmap={h.showHeatmap}
|
|
onToggleHeatmap={() => h.setShowHeatmap(prev => !prev)}
|
|
onFileUpload={h.handleFileUpload}
|
|
onManualOCR={h.handleManualOCR}
|
|
onClearImage={h.clearUploadedImage}
|
|
onSendToTraining={h.sendToTraining}
|
|
/>
|
|
)}
|
|
|
|
{h.activeTab === 'batch' && <TabBatch />}
|
|
|
|
{h.activeTab === 'training' && (
|
|
<TabTraining
|
|
status={h.status}
|
|
examples={h.examples}
|
|
trainingImage={h.trainingImage}
|
|
trainingText={h.trainingText}
|
|
fineTuning={h.fineTuning}
|
|
settings={h.settings}
|
|
showTrainingDashboard={h.showTrainingDashboard}
|
|
onSetTrainingImage={h.setTrainingImage}
|
|
onSetTrainingText={h.setTrainingText}
|
|
onAddExample={h.handleAddTrainingExample}
|
|
onFineTune={h.handleFineTune}
|
|
onToggleDashboard={() => h.setShowTrainingDashboard(prev => !prev)}
|
|
/>
|
|
)}
|
|
|
|
{h.activeTab === 'architecture' && <TabArchitecture />}
|
|
|
|
{h.activeTab === 'settings' && (
|
|
<TabSettings
|
|
settings={h.settings}
|
|
settingsSaved={h.settingsSaved}
|
|
onUpdateSettings={h.setSettings}
|
|
onSave={h.saveSettings}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|