[split-required] Split final batch of monoliths >1000 LOC
Python (6 files in klausur-service): - rbac.py (1,132 → 4), admin_api.py (1,012 → 4) - routes/eh.py (1,111 → 4), ocr_pipeline_geometry.py (1,105 → 5) Python (2 files in backend-lehrer): - unit_api.py (1,226 → 6), game_api.py (1,129 → 5) Website (6 page files): - 4x klausur-korrektur pages (1,249-1,328 LOC each) → shared components in website/components/klausur-korrektur/ (17 shared files) - companion (1,057 → 10), magic-help (1,017 → 8) All re-export barrels preserve backward compatibility. Zero import errors verified. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
182
website/app/admin/magic-help/_components/TrainingTab.tsx
Normal file
182
website/app/admin/magic-help/_components/TrainingTab.tsx
Normal file
@@ -0,0 +1,182 @@
|
||||
'use client'
|
||||
|
||||
import type { TrOCRStatus, TrainingExample, MagicSettings } from './types'
|
||||
|
||||
interface TrainingTabProps {
|
||||
status: TrOCRStatus | null
|
||||
examples: TrainingExample[]
|
||||
trainingImage: File | null
|
||||
setTrainingImage: (file: File | null) => void
|
||||
trainingText: string
|
||||
setTrainingText: (text: string) => void
|
||||
fineTuning: boolean
|
||||
settings: MagicSettings
|
||||
handleAddTrainingExample: () => void
|
||||
handleFineTune: () => void
|
||||
}
|
||||
|
||||
export default function TrainingTab({
|
||||
status,
|
||||
examples,
|
||||
trainingImage,
|
||||
setTrainingImage,
|
||||
trainingText,
|
||||
setTrainingText,
|
||||
fineTuning,
|
||||
settings,
|
||||
handleAddTrainingExample,
|
||||
handleFineTune,
|
||||
}: TrainingTabProps) {
|
||||
const examplesCount = status?.training_examples_count || 0
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Training Overview */}
|
||||
<div className="bg-gray-800/50 border border-gray-700 rounded-xl p-6">
|
||||
<h2 className="text-lg font-semibold text-white mb-4">Training mit LoRA</h2>
|
||||
<p className="text-sm text-gray-400 mb-4">
|
||||
LoRA (Low-Rank Adaptation) ermöglicht effizientes Fine-Tuning ohne das Basismodell zu verändern.
|
||||
Das Training erfolgt lokal auf Ihrem System.
|
||||
</p>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
||||
<div className="bg-gray-900/50 rounded-lg p-4 text-center">
|
||||
<div className="text-3xl font-bold text-white">{examplesCount}</div>
|
||||
<div className="text-xs text-gray-400">Trainingsbeispiele</div>
|
||||
</div>
|
||||
<div className="bg-gray-900/50 rounded-lg p-4 text-center">
|
||||
<div className="text-3xl font-bold text-white">10</div>
|
||||
<div className="text-xs text-gray-400">Minimum benötigt</div>
|
||||
</div>
|
||||
<div className="bg-gray-900/50 rounded-lg p-4 text-center">
|
||||
<div className="text-3xl font-bold text-white">{settings.loraRank}</div>
|
||||
<div className="text-xs text-gray-400">LoRA Rank</div>
|
||||
</div>
|
||||
<div className="bg-gray-900/50 rounded-lg p-4 text-center">
|
||||
<div className="text-3xl font-bold text-white">{status?.has_lora_adapter ? '✓' : '✗'}</div>
|
||||
<div className="text-xs text-gray-400">Adapter aktiv</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress Bar */}
|
||||
<div className="mb-6">
|
||||
<div className="flex justify-between text-sm mb-1">
|
||||
<span className="text-gray-400">Fortschritt zum Fine-Tuning</span>
|
||||
<span className="text-gray-400">{Math.min(100, (examplesCount / 10) * 100).toFixed(0)}%</span>
|
||||
</div>
|
||||
<div className="h-2 bg-gray-700 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-purple-500 to-blue-500 transition-all duration-500"
|
||||
style={{ width: `${Math.min(100, (examplesCount / 10) * 100)}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Add Training Example */}
|
||||
<div className="bg-gray-800/50 border border-gray-700 rounded-xl p-6">
|
||||
<h2 className="text-lg font-semibold text-white mb-4">Trainingsbeispiel hinzufügen</h2>
|
||||
<p className="text-sm text-gray-400 mb-4">
|
||||
Lade ein Bild mit handgeschriebenem Text hoch und gib die korrekte Transkription ein.
|
||||
</p>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">Bild</label>
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
className="w-full bg-gray-900 border border-gray-700 rounded-lg px-3 py-2 text-sm"
|
||||
onChange={(e) => setTrainingImage(e.target.files?.[0] || null)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">Korrekter Text (Ground Truth)</label>
|
||||
<textarea
|
||||
className="w-full bg-gray-900 border border-gray-700 rounded-lg px-3 py-2 text-sm text-white resize-none"
|
||||
rows={3}
|
||||
placeholder="Gib hier den korrekten Text ein..."
|
||||
value={trainingText}
|
||||
onChange={(e) => setTrainingText(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleAddTrainingExample}
|
||||
className="w-full px-4 py-2 bg-purple-600 hover:bg-purple-700 rounded-lg text-sm font-medium transition-colors"
|
||||
>
|
||||
+ Trainingsbeispiel hinzufügen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Fine-Tuning */}
|
||||
<div className="bg-gray-800/50 border border-gray-700 rounded-xl p-6">
|
||||
<h2 className="text-lg font-semibold text-white mb-4">Fine-Tuning starten</h2>
|
||||
<p className="text-sm text-gray-400 mb-4">
|
||||
Trainiere das Modell mit den gesammelten Beispielen. Der Prozess dauert
|
||||
je nach Anzahl der Beispiele einige Minuten.
|
||||
</p>
|
||||
|
||||
<div className="bg-gray-900/50 rounded-lg p-4 mb-4">
|
||||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||||
<div>
|
||||
<span className="text-gray-400">Epochen:</span>
|
||||
<span className="text-white ml-2">{settings.epochs}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-gray-400">Learning Rate:</span>
|
||||
<span className="text-white ml-2">{settings.learningRate}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-gray-400">LoRA Rank:</span>
|
||||
<span className="text-white ml-2">{settings.loraRank}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-gray-400">Batch Size:</span>
|
||||
<span className="text-white ml-2">{settings.batchSize}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleFineTune}
|
||||
disabled={fineTuning || examplesCount < 10}
|
||||
className="w-full px-4 py-2 bg-green-600 hover:bg-green-700 disabled:bg-gray-700 disabled:cursor-not-allowed rounded-lg text-sm font-medium transition-colors"
|
||||
>
|
||||
{fineTuning ? (
|
||||
<span className="flex items-center justify-center gap-2">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
|
||||
Fine-Tuning läuft...
|
||||
</span>
|
||||
) : (
|
||||
'Fine-Tuning starten'
|
||||
)}
|
||||
</button>
|
||||
|
||||
{examplesCount < 10 && (
|
||||
<p className="text-xs text-yellow-400 mt-2 text-center">
|
||||
Noch {10 - examplesCount} Beispiele benötigt
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Training Examples List */}
|
||||
{examples.length > 0 && (
|
||||
<div className="bg-gray-800/50 border border-gray-700 rounded-xl p-6">
|
||||
<h2 className="text-lg font-semibold text-white mb-4">Trainingsbeispiele ({examples.length})</h2>
|
||||
<div className="space-y-2 max-h-64 overflow-y-auto">
|
||||
{examples.map((ex, i) => (
|
||||
<div key={i} className="flex items-center gap-4 bg-gray-900/50 rounded-lg p-3">
|
||||
<span className="text-gray-500 font-mono text-sm w-8">{i + 1}.</span>
|
||||
<span className="text-white text-sm flex-1 truncate">{ex.ground_truth}</span>
|
||||
<span className="text-gray-500 text-xs">{new Date(ex.created_at).toLocaleDateString('de-DE')}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user