From 9ba420fa91115aeb7cc153cca5cec4231055bdda Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Fri, 24 Apr 2026 16:02:04 +0200 Subject: [PATCH] Fix: Remove broken getKlausurApiUrl and clean up empty lines sed replacement left orphaned hostname references in story page and empty lines in getApiBase functions. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/rules/loc-exceptions.txt | 9 + .claude/rules/ocr-pipeline-extensions.md | 7 +- .../magic-help/_components/GlobalOverlays.tsx | 64 + .../_components/TabArchitecture.tsx | 185 + .../ai/magic-help/_components/TabBatch.tsx | 53 + .../ai/magic-help/_components/TabOverview.tsx | 127 + .../ai/magic-help/_components/TabSettings.tsx | 226 + .../ai/magic-help/_components/TabTest.tsx | 304 + .../ai/magic-help/_components/TabTraining.tsx | 333 ++ .../ai/magic-help/_components/index.ts | 7 + .../app/(admin)/ai/magic-help/page.tsx | 1567 +----- .../app/(admin)/ai/magic-help/types.ts | 71 + .../app/(admin)/ai/magic-help/useMagicHelp.ts | 382 ++ .../_components/ArchitectureTab.tsx | 212 + .../_components/DataSourcesTab.tsx | 171 + .../_components/DatasetOverview.tsx | 60 + .../_components/NewTrainingModal.tsx | 277 + .../_components/SharedWidgets.tsx | 168 + .../_components/TrainingJobCard.tsx | 126 + .../app/(admin)/ai/rag-pipeline/api.ts | 146 + .../app/(admin)/ai/rag-pipeline/page.tsx | 1527 +---- .../app/(admin)/ai/rag-pipeline/types.ts | 63 + .../(admin)/ai/rag-pipeline/useRagPipeline.ts | 147 + .../(admin)/ai/rag/_components/DataTab.tsx | 195 + .../ai/rag/_components/IngestionTab.tsx | 69 + .../app/(admin)/ai/rag/_components/MapTab.tsx | 373 ++ .../ai/rag/_components/MapTabSections.tsx | 199 + .../ai/rag/_components/OverviewTab.tsx | 113 + .../ai/rag/_components/PipelineTab.tsx | 410 ++ .../ai/rag/_components/RegulationsTab.tsx | 451 ++ .../(admin)/ai/rag/_components/SearchTab.tsx | 97 + .../app/(admin)/ai/rag/_hooks/useRAGPage.ts | 441 ++ admin-lehrer/app/(admin)/ai/rag/page.tsx | 2605 +-------- admin-lehrer/app/(admin)/ai/rag/rag-data.ts | 352 ++ .../app/(admin)/ai/rag/rag-sources.ts | 221 + admin-lehrer/app/(admin)/ai/rag/types.ts | 183 + .../_components/FailedTestsList.tsx | 199 + .../ai/test-quality/_components/GoldenTab.tsx | 77 + .../ai/test-quality/_components/GuideTab.tsx | 279 + .../_components/IntentScoresChart.tsx | 40 + .../test-quality/_components/MetricCard.tsx | 54 + .../test-quality/_components/OverviewTab.tsx | 108 + .../ai/test-quality/_components/RagTab.tsx | 111 + .../test-quality/_components/SyntheticTab.tsx | 81 + .../_components/TestRunsTable.tsx | 62 + .../_components/TestSuiteCard.tsx | 99 + .../_components/ToastContainer.tsx | 55 + .../test-quality/_components/TrendChart.tsx | 74 + .../ai/test-quality/_components/index.ts | 12 + .../app/(admin)/ai/test-quality/constants.ts | 41 + .../app/(admin)/ai/test-quality/page.tsx | 1452 +---- .../(admin)/ai/test-quality/useTestQuality.ts | 219 + .../ci-cd/_components/DeploymentsTab.tsx | 168 + .../ci-cd/_components/OverviewTab.tsx | 278 + .../ci-cd/_components/PipelinesTab.tsx | 145 + .../ci-cd/_components/SchedulerTab.tsx | 286 + .../ci-cd/_components/SetupTab.tsx | 166 + .../ci-cd/_components/WoodpeckerTab.tsx | 325 ++ .../ci-cd/_components/helpers.tsx | 42 + .../app/(admin)/infrastructure/ci-cd/page.tsx | 1619 +----- .../app/(admin)/infrastructure/ci-cd/types.ts | 105 + .../infrastructure/ci-cd/useCiCdData.ts | 244 + .../tests/_components/BacklogTab.tsx | 490 ++ .../tests/_components/CoverageChart.tsx | 82 + .../tests/_components/GuideTab.tsx | 224 + .../tests/_components/MetricCard.tsx | 53 + .../tests/_components/ServiceTestCard.tsx | 156 + .../tests/_components/TestRunsTable.tsx | 64 + .../tests/_components/ToastContainer.tsx | 55 + .../tests/_hooks/useTestDashboard.ts | 310 ++ .../infrastructure/tests/_lib/constants.ts | 31 + .../app/(admin)/infrastructure/tests/page.tsx | 1442 +---- admin-lehrer/lib/sdk/types.ts | 2108 ------- .../lib/sdk/types/ai-act-obligations.ts | 46 + admin-lehrer/lib/sdk/types/assessment.ts | 39 + admin-lehrer/lib/sdk/types/checkpoint.ts | 55 + admin-lehrer/lib/sdk/types/company-profile.ts | 238 + admin-lehrer/lib/sdk/types/compliance.ts | 85 + admin-lehrer/lib/sdk/types/core.ts | 88 + .../lib/sdk/types/document-generator.ts | 339 ++ admin-lehrer/lib/sdk/types/documentation.ts | 239 + admin-lehrer/lib/sdk/types/dsfa-rag.ts | 263 + admin-lehrer/lib/sdk/types/dsfa.ts | 39 + admin-lehrer/lib/sdk/types/helpers.ts | 187 + admin-lehrer/lib/sdk/types/index.ts | 22 + admin-lehrer/lib/sdk/types/risk.ts | 42 + .../lib/sdk/types/screening-security.ts | 99 + admin-lehrer/lib/sdk/types/sdk-flow.ts | 429 ++ admin-lehrer/lib/sdk/types/state.ts | 197 + .../api/handlers/ai_extraction_handlers.go | 261 - .../handlers/ai_extraction_handlers_batch.go | 272 + .../internal/api/handlers/policy_handlers.go | 284 - .../api/handlers/policy_handlers_rules.go | 293 + .../internal/database/repository.go | 391 -- .../internal/database/repository_staff.go | 398 ++ edu-search-service/internal/policy/store.go | 809 --- .../internal/policy/store_audit.go | 411 ++ .../internal/policy/store_sources.go | 417 ++ edu-search-service/internal/search/search.go | 349 -- .../internal/search/search_query.go | 350 ++ .../internal/staff/staff_crawler.go | 1269 +---- .../internal/staff/staff_crawler_discovery.go | 247 + .../internal/staff/staff_crawler_enrich.go | 364 ++ .../internal/staff/staff_crawler_extract.go | 495 ++ klausur-service/backend/cv_layout.py | 3557 +----------- klausur-service/backend/cv_layout_analyze.py | 257 + klausur-service/backend/cv_layout_classify.py | 494 ++ .../backend/cv_layout_classify_position.py | 218 + .../backend/cv_layout_column_refine.py | 458 ++ klausur-service/backend/cv_layout_columns.py | 589 ++ .../backend/cv_layout_detection.py | 479 ++ .../backend/cv_layout_row_regularize.py | 329 ++ klausur-service/backend/cv_layout_rows.py | 352 ++ klausur-service/backend/cv_layout_scoring.py | 441 ++ klausur-service/backend/cv_ocr_cell_filter.py | 493 ++ .../backend/cv_ocr_cell_phonetics.py | 189 + klausur-service/backend/cv_ocr_engines.py | 1877 +------ klausur-service/backend/cv_ocr_ipa_lookup.py | 476 ++ klausur-service/backend/cv_ocr_ipa_repair.py | 287 + .../backend/cv_ocr_vocab_postprocess.py | 318 ++ .../backend/cv_ocr_word_assembly.py | 134 + klausur-service/backend/dsfa_chunking.py | 140 + .../backend/dsfa_corpus_ingestion.py | 1695 +----- klausur-service/backend/dsfa_corpus_store.py | 239 + .../backend/dsfa_qdrant_service.py | 157 + .../backend/dsfa_sources_registry.py | 1140 ++++ .../backend/grid_build_cell_ops.py | 305 + klausur-service/backend/grid_build_cleanup.py | 390 ++ klausur-service/backend/grid_build_core.py | 1961 +------ .../backend/grid_build_finalize.py | 452 ++ .../backend/grid_build_text_ops.py | 489 ++ klausur-service/backend/grid_build_zones.py | 462 ++ .../backend/vocab_worksheet_analysis_api.py | 472 ++ .../backend/vocab_worksheet_api.py | 2396 +------- .../backend/vocab_worksheet_compare_api.py | 545 ++ .../backend/vocab_worksheet_extraction.py | 325 ++ .../backend/vocab_worksheet_generation.py | 260 + .../backend/vocab_worksheet_models.py | 86 + .../backend/vocab_worksheet_ocr.py | 481 ++ .../backend/vocab_worksheet_upload_api.py | 490 ++ school-service/internal/seed/seed_data.go | 357 -- .../internal/seed/seed_data_students.go | 366 ++ .../internal/services/grade_service.go | 444 -- .../internal/services/grade_service_calc.go | 449 ++ .../app/learn/[unitId]/flashcards/page.tsx | 3 - studio-v2/app/learn/[unitId]/quiz/page.tsx | 3 - studio-v2/app/learn/[unitId]/story/page.tsx | 10 - studio-v2/app/learn/[unitId]/type/page.tsx | 3 - .../components/dashboard/LearningProgress.tsx | 3 - .../system-info-configs/index_original.ts | 4899 ----------------- 150 files changed, 30231 insertions(+), 32053 deletions(-) create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/_components/GlobalOverlays.tsx create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/_components/TabArchitecture.tsx create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/_components/TabBatch.tsx create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/_components/TabOverview.tsx create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/_components/TabSettings.tsx create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/_components/TabTest.tsx create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/_components/TabTraining.tsx create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/_components/index.ts create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/types.ts create mode 100644 admin-lehrer/app/(admin)/ai/magic-help/useMagicHelp.ts create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/_components/ArchitectureTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/_components/DataSourcesTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/_components/DatasetOverview.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/_components/NewTrainingModal.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/_components/SharedWidgets.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/_components/TrainingJobCard.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/api.ts create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/types.ts create mode 100644 admin-lehrer/app/(admin)/ai/rag-pipeline/useRagPipeline.ts create mode 100644 admin-lehrer/app/(admin)/ai/rag/_components/DataTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag/_components/IngestionTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag/_components/MapTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag/_components/MapTabSections.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag/_components/OverviewTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag/_components/PipelineTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag/_components/RegulationsTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag/_components/SearchTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/rag/_hooks/useRAGPage.ts create mode 100644 admin-lehrer/app/(admin)/ai/rag/rag-data.ts create mode 100644 admin-lehrer/app/(admin)/ai/rag/rag-sources.ts create mode 100644 admin-lehrer/app/(admin)/ai/rag/types.ts create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/FailedTestsList.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/GoldenTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/GuideTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/IntentScoresChart.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/MetricCard.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/OverviewTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/RagTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/SyntheticTab.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/TestRunsTable.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/TestSuiteCard.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/ToastContainer.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/TrendChart.tsx create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/_components/index.ts create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/constants.ts create mode 100644 admin-lehrer/app/(admin)/ai/test-quality/useTestQuality.ts create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/_components/DeploymentsTab.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/_components/OverviewTab.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/_components/PipelinesTab.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/_components/SchedulerTab.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/_components/SetupTab.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/_components/WoodpeckerTab.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/_components/helpers.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/types.ts create mode 100644 admin-lehrer/app/(admin)/infrastructure/ci-cd/useCiCdData.ts create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_components/BacklogTab.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_components/CoverageChart.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_components/GuideTab.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_components/MetricCard.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_components/ServiceTestCard.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_components/TestRunsTable.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_components/ToastContainer.tsx create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_hooks/useTestDashboard.ts create mode 100644 admin-lehrer/app/(admin)/infrastructure/tests/_lib/constants.ts delete mode 100644 admin-lehrer/lib/sdk/types.ts create mode 100644 admin-lehrer/lib/sdk/types/ai-act-obligations.ts create mode 100644 admin-lehrer/lib/sdk/types/assessment.ts create mode 100644 admin-lehrer/lib/sdk/types/checkpoint.ts create mode 100644 admin-lehrer/lib/sdk/types/company-profile.ts create mode 100644 admin-lehrer/lib/sdk/types/compliance.ts create mode 100644 admin-lehrer/lib/sdk/types/core.ts create mode 100644 admin-lehrer/lib/sdk/types/document-generator.ts create mode 100644 admin-lehrer/lib/sdk/types/documentation.ts create mode 100644 admin-lehrer/lib/sdk/types/dsfa-rag.ts create mode 100644 admin-lehrer/lib/sdk/types/dsfa.ts create mode 100644 admin-lehrer/lib/sdk/types/helpers.ts create mode 100644 admin-lehrer/lib/sdk/types/index.ts create mode 100644 admin-lehrer/lib/sdk/types/risk.ts create mode 100644 admin-lehrer/lib/sdk/types/screening-security.ts create mode 100644 admin-lehrer/lib/sdk/types/sdk-flow.ts create mode 100644 admin-lehrer/lib/sdk/types/state.ts create mode 100644 edu-search-service/internal/api/handlers/ai_extraction_handlers_batch.go create mode 100644 edu-search-service/internal/api/handlers/policy_handlers_rules.go create mode 100644 edu-search-service/internal/database/repository_staff.go create mode 100644 edu-search-service/internal/policy/store_audit.go create mode 100644 edu-search-service/internal/policy/store_sources.go create mode 100644 edu-search-service/internal/search/search_query.go create mode 100644 edu-search-service/internal/staff/staff_crawler_discovery.go create mode 100644 edu-search-service/internal/staff/staff_crawler_enrich.go create mode 100644 edu-search-service/internal/staff/staff_crawler_extract.go create mode 100644 klausur-service/backend/cv_layout_analyze.py create mode 100644 klausur-service/backend/cv_layout_classify.py create mode 100644 klausur-service/backend/cv_layout_classify_position.py create mode 100644 klausur-service/backend/cv_layout_column_refine.py create mode 100644 klausur-service/backend/cv_layout_columns.py create mode 100644 klausur-service/backend/cv_layout_detection.py create mode 100644 klausur-service/backend/cv_layout_row_regularize.py create mode 100644 klausur-service/backend/cv_layout_rows.py create mode 100644 klausur-service/backend/cv_layout_scoring.py create mode 100644 klausur-service/backend/cv_ocr_cell_filter.py create mode 100644 klausur-service/backend/cv_ocr_cell_phonetics.py create mode 100644 klausur-service/backend/cv_ocr_ipa_lookup.py create mode 100644 klausur-service/backend/cv_ocr_ipa_repair.py create mode 100644 klausur-service/backend/cv_ocr_vocab_postprocess.py create mode 100644 klausur-service/backend/cv_ocr_word_assembly.py create mode 100644 klausur-service/backend/dsfa_chunking.py create mode 100644 klausur-service/backend/dsfa_corpus_store.py create mode 100644 klausur-service/backend/dsfa_qdrant_service.py create mode 100644 klausur-service/backend/dsfa_sources_registry.py create mode 100644 klausur-service/backend/grid_build_cell_ops.py create mode 100644 klausur-service/backend/grid_build_cleanup.py create mode 100644 klausur-service/backend/grid_build_finalize.py create mode 100644 klausur-service/backend/grid_build_text_ops.py create mode 100644 klausur-service/backend/grid_build_zones.py create mode 100644 klausur-service/backend/vocab_worksheet_analysis_api.py create mode 100644 klausur-service/backend/vocab_worksheet_compare_api.py create mode 100644 klausur-service/backend/vocab_worksheet_extraction.py create mode 100644 klausur-service/backend/vocab_worksheet_generation.py create mode 100644 klausur-service/backend/vocab_worksheet_models.py create mode 100644 klausur-service/backend/vocab_worksheet_ocr.py create mode 100644 klausur-service/backend/vocab_worksheet_upload_api.py create mode 100644 school-service/internal/seed/seed_data_students.go create mode 100644 school-service/internal/services/grade_service_calc.go delete mode 100644 website/components/admin/system-info-configs/index_original.ts diff --git a/.claude/rules/loc-exceptions.txt b/.claude/rules/loc-exceptions.txt index 0f50bfd..c00fe9f 100644 --- a/.claude/rules/loc-exceptions.txt +++ b/.claude/rules/loc-exceptions.txt @@ -15,6 +15,15 @@ **/tests/test_rbac.py | owner=klausur | reason=RBAC Test-Matrix | review=2026-07-01 **/tests/test_grid_editor_api.py | owner=klausur | reason=Grid Editor Integrationstests | review=2026-07-01 +# Pure Data Registries (keine Logik, nur Daten-Definitionen) +**/dsfa_sources_registry.py | owner=klausur | reason=Pure data registry (license + source definitions, no logic) | review=2027-01-01 + +# Algorithmic monolith — detect_column_geometry() allein 411 LOC, nicht weiter teilbar +**/cv_layout_columns.py | owner=klausur | reason=detect_column_geometry ist eine einzelne 411-LOC Funktion (Whitespace-Gap-Analyse) | review=2026-10-01 + +# Two indivisible route handlers (~230 LOC each) that cannot be split further +**/vocab_worksheet_compare_api.py | owner=klausur | reason=compare_ocr_methods (234 LOC) + analyze_grid (255 LOC), each a single cohesive handler | review=2026-10-01 + # Legacy — TEMPORAER bis Refactoring abgeschlossen # Dateien hier werden Phase fuer Phase abgearbeitet und entfernt. # KEINE neuen Ausnahmen ohne [guardrail-change] Commit-Marker! diff --git a/.claude/rules/ocr-pipeline-extensions.md b/.claude/rules/ocr-pipeline-extensions.md index a2c8c1f..4f489e8 100644 --- a/.claude/rules/ocr-pipeline-extensions.md +++ b/.claude/rules/ocr-pipeline-extensions.md @@ -199,7 +199,12 @@ GET /api/v1/ocr-pipeline/sessions/{id}/unified-grid | Datei | Zeilen | Beschreibung | |-------|--------|--------------| -| `grid_build_core.py` | 1943 | `_build_grid_core()` — Haupt-Grid-Aufbau | +| `grid_build_core.py` | 213 | `_build_grid_core()` — Orchestrator (ruft Phase-Module) | +| `grid_build_zones.py` | 462 | Phase 2: Bildverarbeitung, Grafik-/Box-Erkennung, Zonen | +| `grid_build_cleanup.py` | 390 | Phase 3: Junk-Zeilen, Artefakte, Pipes, Randstreifen | +| `grid_build_text_ops.py` | 489 | Phase 4+5a: Farben, Ueberschriften, IPA, Seitenreferenzen | +| `grid_build_cell_ops.py` | 305 | Phase 5b: Bullet-Entfernung, Wort-Reihenfolge, max_columns | +| `grid_build_finalize.py` | 452 | Phase 5c+6: Woerterbuch, Silben, Rechtschreibung, Ergebnis | | `grid_editor_api.py` | 474 | REST-Endpoints (build, save, get, gutter, box, unified) | | `grid_editor_helpers.py` | 1737 | Helper: Spalten, Rows, Cells, Colspan, Header | | `smart_spell.py` | 587 | SmartSpellChecker | diff --git a/admin-lehrer/app/(admin)/ai/magic-help/_components/GlobalOverlays.tsx b/admin-lehrer/app/(admin)/ai/magic-help/_components/GlobalOverlays.tsx new file mode 100644 index 0000000..9f94f9b --- /dev/null +++ b/admin-lehrer/app/(admin)/ai/magic-help/_components/GlobalOverlays.tsx @@ -0,0 +1,64 @@ +'use client' + +interface GlobalDragOverlayProps { + active: boolean +} + +export function GlobalDragOverlay({ active }: GlobalDragOverlayProps) { + if (!active) return null + + return ( +
+
+
📄
+
Bild hier ablegen
+
PNG, JPG - Handgeschriebener Text
+
+
+ ) +} + +interface KeyboardShortcutsModalProps { + open: boolean + onClose: () => void +} + +export function KeyboardShortcutsModal({ open, onClose }: KeyboardShortcutsModalProps) { + if (!open) return null + + return ( +
+
e.stopPropagation()}> +

Tastenkuerzel

+
+
+ Bild einfuegen + Ctrl+V +
+
+ OCR starten + Ctrl+Enter +
+
+ Tab wechseln + Alt+1-6 +
+
+ Bild entfernen + Escape +
+
+ Shortcuts anzeigen + ? +
+
+ +
+
+ ) +} diff --git a/admin-lehrer/app/(admin)/ai/magic-help/_components/TabArchitecture.tsx b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabArchitecture.tsx new file mode 100644 index 0000000..4fa6fdd --- /dev/null +++ b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabArchitecture.tsx @@ -0,0 +1,185 @@ +'use client' + +export function TabArchitecture() { + return ( +
+ {/* Architecture Diagram */} + + + {/* Components */} +
+ + + + +
+ + {/* Data Flow */} + +
+ ) +} + +/* ------------------------------------------------------------------ */ + +function ArchitectureDiagram() { + return ( +
+

Systemarchitektur

+ +
+
+{`┌─────────────────────────────────────────────────────────────────────────────┐
+│                          MAGIC HELP ARCHITEKTUR                              │
+├─────────────────────────────────────────────────────────────────────────────┤
+│                                                                             │
+│  ┌───────────────┐         ┌──────────────────┐         ┌───────────────┐  │
+│  │   FRONTEND    │         │    BACKEND       │         │    STORAGE    │  │
+│  │   (Next.js)   │         │    (FastAPI)     │         │               │  │
+│  │               │         │                  │         │               │  │
+│  │  ┌─────────┐  │  REST   │  ┌────────────┐  │         │  ┌─────────┐  │  │
+│  │  │ Admin   │──┼─────────┼──│ TrOCR      │  │         │  │ Models  │  │  │
+│  │  │ Panel   │  │         │  │ Service    │──┼─────────┼──│ (ONNX)  │  │  │
+│  │  └─────────┘  │         │  └────────────┘  │         │  └─────────┘  │  │
+│  │               │         │        │         │         │               │  │
+│  │  ┌─────────┐  │  WebSocket│  ┌────────────┐  │         │  ┌─────────┐  │  │
+│  │  │ Lehrer  │──┼─────────┼──│ Klausur    │  │         │  │ LoRA    │  │  │
+│  │  │ Portal  │  │         │  │ Processor  │──┼─────────┼──│ Adapter │  │  │
+│  │  └─────────┘  │         │  └────────────┘  │         │  └─────────┘  │  │
+│  │               │         │        │         │         │               │  │
+│  └───────────────┘         │  ┌────────────┐  │         │  ┌─────────┐  │  │
+│                            │  │ Pseudo-    │  │         │  │Training │  │  │
+│                            │  │ nymizer    │──┼─────────┼──│ Data    │  │  │
+│                            │  └────────────┘  │         │  └─────────┘  │  │
+│                            │                  │         │               │  │
+│                            └──────────────────┘         └───────────────┘  │
+│                                     │                                      │
+│                                     │ (nur pseudonymisiert)                │
+│                                     ▼                                      │
+│                            ┌──────────────────┐                            │
+│                            │  CLOUD LLM       │                            │
+│                            │  (SysEleven)     │                            │
+│                            │  Namespace-      │                            │
+│                            │  Isolation       │                            │
+│                            └──────────────────┘                            │
+│                                                                             │
+└─────────────────────────────────────────────────────────────────────────────┘`}
+        
+
+
+ ) +} + +interface ComponentCardProps { + icon: string + title: string + description: string + specs: Array<{ label: string; value: string }> +} + +function ComponentCard({ icon, title, description, specs }: ComponentCardProps) { + return ( +
+

+ {icon} {title} +

+
+ {specs.map((spec) => ( +
+ {spec.label} + {spec.value} +
+ ))} +
+

{description}

+
+ ) +} + +const DATA_FLOW_STEPS = [ + { + num: 1, + color: 'bg-blue-100 text-blue-600', + title: 'Lokale Header-Extraktion', + desc: 'TrOCR erkennt Schuelernamen, Klasse und Fach direkt im Browser/PWA (offline-faehig)', + }, + { + num: 2, + color: 'bg-purple-100 text-purple-600', + title: 'Pseudonymisierung', + desc: 'Namen werden durch QR-Code Tokens ersetzt, Mapping bleibt lokal', + }, + { + num: 3, + color: 'bg-green-100 text-green-600', + title: 'Cloud-Korrektur', + desc: 'Nur pseudonymisierte Dokument-Tokens werden an die KI gesendet', + }, + { + num: 4, + color: 'bg-yellow-100 text-yellow-600', + title: 'Re-Identifikation', + desc: 'Ergebnisse werden lokal mit dem Mapping wieder den echten Namen zugeordnet', + }, +] + +function DataFlowCard() { + return ( +
+

Datenfluss

+
+ {DATA_FLOW_STEPS.map((step) => ( +
+
+ {step.num} +
+
+
{step.title}
+
{step.desc}
+
+
+ ))} +
+
+ ) +} diff --git a/admin-lehrer/app/(admin)/ai/magic-help/_components/TabBatch.tsx b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabBatch.tsx new file mode 100644 index 0000000..7d19c0e --- /dev/null +++ b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabBatch.tsx @@ -0,0 +1,53 @@ +'use client' + +import { BatchUploader } from '@/components/ai/BatchUploader' +import { API_BASE } from '../types' + +export function TabBatch() { + return ( +
+ {/* Batch OCR Processing */} +
+

Batch-Verarbeitung

+

+ Verarbeite mehrere Bilder gleichzeitig mit Echtzeit-Fortschrittsanzeige. + Die Ergebnisse werden per Server-Sent Events gestreamt. +

+ + { + console.log('Batch complete:', results) + }} + /> +
+ + {/* Batch Processing Info */} +
+
+
🚀
+

Parallele Verarbeitung

+

+ Mehrere Bilder werden parallel verarbeitet fuer maximale Geschwindigkeit. +

+
+
+
💾
+

Smart Caching

+

+ Identische Bilder werden automatisch aus dem Cache geladen (unter 50ms). +

+
+
+
📊
+

Live-Fortschritt

+

+ Echtzeit-Updates via Server-Sent Events zeigen den Verarbeitungsfortschritt. +

+
+
+
+ ) +} diff --git a/admin-lehrer/app/(admin)/ai/magic-help/_components/TabOverview.tsx b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabOverview.tsx new file mode 100644 index 0000000..bff7d94 --- /dev/null +++ b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabOverview.tsx @@ -0,0 +1,127 @@ +'use client' + +import { SkeletonText } from '@/components/common/SkeletonText' +import type { TrOCRStatus } from '../types' + +interface TabOverviewProps { + status: TrOCRStatus | null + loading: boolean + onRefresh: () => void +} + +export function TabOverview({ status, loading, onRefresh }: TabOverviewProps) { + return ( +
+ {/* Status Card */} +
+
+

Systemstatus

+ +
+ + {loading ? ( +
+ {[1, 2, 3, 4].map((i) => ( +
+ +
+
+ ))} +
+ ) : status?.status === 'available' ? ( +
+
+
{status.model_name || 'trocr-base'}
+
Modell
+
+
+
{status.device || 'CPU'}
+
Geraet
+
+
+
{status.training_examples_count || 0}
+
Trainingsbeispiele
+
+
+
{status.has_lora_adapter ? 'Aktiv' : 'Keiner'}
+
LoRA Adapter
+
+
+ ) : status?.status === 'not_installed' ? ( +
+

TrOCR ist nicht installiert. Fuehre aus:

+ {status.install_command} +
+ ) : ( +
{status?.error || 'Unbekannter Fehler'}
+ )} +
+ + {/* Quick Overview Cards */} +
+
+
🎯
+

Handschrifterkennung

+

+ TrOCR erkennt automatisch handgeschriebenen Text in Klausuren. + Das Modell wurde speziell fuer deutsche Handschriften optimiert. +

+
+
+
🔒
+

Privacy by Design

+

+ Alle Daten werden lokal verarbeitet. Schuelernamen werden durch + QR-Codes pseudonymisiert - DSGVO-konform. +

+
+
+
📈
+

Kontinuierliches Lernen

+

+ Mit LoRA Fine-Tuning passt sich das Modell an individuelle + Handschriften an - ohne das Basismodell zu veraendern. +

+
+
+ + {/* Workflow Overview */} +
+

Magic Onboarding Workflow

+
+ {WORKFLOW_STEPS.map((step, i) => ( + + ))} +
+
+
+ ) +} + +const WORKFLOW_STEPS = [ + { icon: '📄', title: '1. Upload', desc: '25 Klausuren hochladen' }, + { icon: '🔍', title: '2. Analyse', desc: 'Lokale OCR in 5-10 Sek' }, + { icon: '✅', title: '3. Bestaetigung', desc: 'Klasse, Schueler, Fach' }, + { icon: '🤖', title: '4. KI-Korrektur', desc: 'Cloud mit Pseudonymisierung' }, + { icon: '📊', title: '5. Integration', desc: 'Notenbuch, Zeugnisse' }, +] + +function WorkflowStep({ step, showArrow }: { step: typeof WORKFLOW_STEPS[number]; showArrow: boolean }) { + return ( + <> +
+ {step.icon} +
+
{step.title}
+
{step.desc}
+
+
+ {showArrow &&
} + + ) +} diff --git a/admin-lehrer/app/(admin)/ai/magic-help/_components/TabSettings.tsx b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabSettings.tsx new file mode 100644 index 0000000..ae136c6 --- /dev/null +++ b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabSettings.tsx @@ -0,0 +1,226 @@ +'use client' + +import type { MagicSettings } from '../types' +import { DEFAULT_SETTINGS } from '../types' + +interface TabSettingsProps { + settings: MagicSettings + settingsSaved: boolean + onUpdateSettings: (settings: MagicSettings) => void + onSave: () => void +} + +export function TabSettings({ settings, settingsSaved, onUpdateSettings, onSave }: TabSettingsProps) { + const update = (partial: Partial) => { + onUpdateSettings({ ...settings, ...partial }) + } + + return ( +
+ {/* OCR Settings */} +
+

OCR Einstellungen

+ +
+ update({ autoDetectLines: v })} + /> + + update({ livePreview: v })} + /> + + update({ soundFeedback: v })} + /> + +
+ + update({ confidenceThreshold: parseFloat(e.target.value) })} + className="w-full" + /> +
+ 0% + {(settings.confidenceThreshold * 100).toFixed(0)}% + 100% +
+
+ +
+ + update({ maxImageSize: parseInt(e.target.value) })} + className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-900" + /> +
Groessere Bilder werden skaliert
+
+ + update({ enableCache: v })} + /> +
+
+ + {/* Training Settings */} +
+

Training Einstellungen

+ +
+
+ + +
+ +
+ + update({ loraAlpha: parseInt(e.target.value) })} + className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-900" + /> +
Empfohlen: 4 x LoRA Rank
+
+ +
+ + update({ epochs: parseInt(e.target.value) })} + className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-900" + /> +
+ +
+ + +
+ +
+ + +
+
+
+ + {/* Save Button */} +
+ + +
+ + {/* Technical Info */} +
+

Technische Informationen

+
+
+ API Endpoint: + /api/klausur/trocr +
+
+ Model Path: + ~/.cache/huggingface +
+
+ LoRA Path: + ./models/lora +
+
+ Training Data: + ./data/training +
+
+
+
+ ) +} + +/* ------------------------------------------------------------------ */ + +function CheckboxSetting({ + label, + description, + checked, + onChange, +}: { + label: string + description: string + checked: boolean + onChange: (value: boolean) => void +}) { + return ( +
+ +
+ ) +} diff --git a/admin-lehrer/app/(admin)/ai/magic-help/_components/TabTest.tsx b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabTest.tsx new file mode 100644 index 0000000..b24bc41 --- /dev/null +++ b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabTest.tsx @@ -0,0 +1,304 @@ +'use client' + +import { SkeletonOCRResult, SkeletonDots } from '@/components/common/SkeletonText' +import { ConfidenceHeatmap } from '@/components/ai/ConfidenceHeatmap' +import type { OCRResult, MagicSettings } from '../types' + +interface TabTestProps { + ocrResult: OCRResult | null + ocrLoading: boolean + imagePreview: string | null + uploadedImage: File | null + settings: MagicSettings + showHeatmap: boolean + onToggleHeatmap: () => void + onFileUpload: (file: File) => void + onManualOCR: () => void + onClearImage: () => void + onSendToTraining: () => void +} + +function getConfidenceColor(confidence: number) { + if (confidence >= 0.9) return 'bg-green-500' + if (confidence >= 0.7) return 'bg-yellow-500' + return 'bg-red-500' +} + +export function TabTest({ + ocrResult, + ocrLoading, + imagePreview, + uploadedImage, + settings, + showHeatmap, + onToggleHeatmap, + onFileUpload, + onManualOCR, + onClearImage, + onSendToTraining, +}: TabTestProps) { + return ( +
+ {/* OCR Test */} +
+

OCR Test

+

+ Teste die Handschrifterkennung mit einem eigenen Bild. Das Ergebnis zeigt + den erkannten Text, Konfidenz und Verarbeitungszeit. + {settings.livePreview && ( + (Live-Vorschau aktiv) + )} +

+ +
+ {/* Upload Area */} + + + {/* Results Area */} + +
+
+ + {/* Confidence Heatmap */} + {imagePreview && ocrResult && ocrResult.confidence > 0 && ( +
+
+

Konfidenz-Visualisierung

+ +
+ {showHeatmap && ( + ({ + text: w.text, + confidence: w.confidence, + bbox: w.bbox as [number, number, number, number] + })) || []} + charConfidences={ocrResult.char_confidences || []} + showLegend={true} + toggleable={true} + /> + )} +
+ )} + + {/* Confidence Interpretation */} +
+

Konfidenz-Interpretation

+
+
+
90-100%
+
Sehr hohe Sicherheit - Text kann direkt uebernommen werden
+
+
+
70-90%
+
Gute Sicherheit - manuelle Ueberpruefung empfohlen
+
+
+
< 70%
+
Niedrige Sicherheit - manuelle Eingabe erforderlich
+
+
+
+
+ ) +} + +/* ------------------------------------------------------------------ */ +/* Sub-components */ +/* ------------------------------------------------------------------ */ + +interface UploadAreaProps { + imagePreview: string | null + uploadedImage: File | null + ocrLoading: boolean + livePreview: boolean + onFileUpload: (file: File) => void + onManualOCR: () => void + onClearImage: () => void +} + +function UploadArea({ imagePreview, uploadedImage, ocrLoading, livePreview, onFileUpload, onManualOCR, onClearImage }: UploadAreaProps) { + return ( +
+
document.getElementById('ocr-file-input')?.click()} + onDragOver={(e) => { e.preventDefault(); e.currentTarget.classList.add('border-purple-500', 'bg-purple-50') }} + onDragLeave={(e) => { e.currentTarget.classList.remove('border-purple-500', 'bg-purple-50') }} + onDrop={(e) => { + e.preventDefault() + e.stopPropagation() + e.currentTarget.classList.remove('border-purple-500', 'bg-purple-50') + const file = e.dataTransfer.files[0] + if (file?.type.startsWith('image/')) onFileUpload(file) + }} + > + {imagePreview ? ( +
+ Hochgeladenes Bild + +
+ ) : ( + <> +
📄
+
Bild hierher ziehen oder klicken zum Hochladen
+
PNG, JPG - Handgeschriebener Text
+
+ oder Ctrl+V zum Einfuegen +
+ + )} +
+ { + const file = e.target.files?.[0] + if (file) onFileUpload(file) + }} + /> + + {uploadedImage && !livePreview && ( + + )} +
+ ) +} + +interface ResultsAreaProps { + ocrResult: OCRResult | null + ocrLoading: boolean + onSendToTraining: () => void +} + +function ResultsArea({ ocrResult, ocrLoading, onSendToTraining }: ResultsAreaProps) { + if (ocrLoading) return + + if (!ocrResult) { + return ( +
+
🔍
+
Lade ein Bild hoch um die Erkennung zu testen
+
+ ) + } + + return ( +
+
+

Erkannter Text:

+
= 0.9 ? 'bg-green-100 text-green-700' : + ocrResult.confidence >= 0.7 ? 'bg-yellow-100 text-yellow-700' : + 'bg-red-100 text-red-700' + }`}> + {(ocrResult.confidence * 100).toFixed(0)}% Konfidenz +
+
+
+        {ocrResult.text || '(Kein Text erkannt)'}
+      
+ + {/* Confidence bar */} +
+
+
+
+
+ +
+
+
Konfidenz
+
{(ocrResult.confidence * 100).toFixed(1)}%
+
+
+
Verarbeitungszeit
+
{ocrResult.processing_time_ms}ms
+
+
+
Modell
+
{ocrResult.model || 'TrOCR'}
+
+
+
LoRA Adapter
+
{ocrResult.has_lora_adapter ? 'Ja' : 'Nein'}
+
+
+ + {ocrResult.confidence < 0.9 && ( +
+

+ Die Erkennung koennte verbessert werden! Moechtest du dieses Beispiel zum Training hinzufuegen? +

+ +
+ )} +
+ ) +} diff --git a/admin-lehrer/app/(admin)/ai/magic-help/_components/TabTraining.tsx b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabTraining.tsx new file mode 100644 index 0000000..c5aa1c8 --- /dev/null +++ b/admin-lehrer/app/(admin)/ai/magic-help/_components/TabTraining.tsx @@ -0,0 +1,333 @@ +'use client' + +import Link from 'next/link' +import { SkeletonDots } from '@/components/common/SkeletonText' +import { TrainingMetrics } from '@/components/ai/TrainingMetrics' +import type { TrOCRStatus, TrainingExample, MagicSettings } from '../types' +import { API_BASE } from '../types' + +interface TabTrainingProps { + status: TrOCRStatus | null + examples: TrainingExample[] + trainingImage: File | null + trainingText: string + fineTuning: boolean + settings: MagicSettings + showTrainingDashboard: boolean + onSetTrainingImage: (file: File | null) => void + onSetTrainingText: (text: string) => void + onAddExample: () => void + onFineTune: () => void + onToggleDashboard: () => void +} + +export function TabTraining({ + status, + examples, + trainingImage, + trainingText, + fineTuning, + settings, + showTrainingDashboard, + onSetTrainingImage, + onSetTrainingText, + onAddExample, + onFineTune, + onToggleDashboard, +}: TabTrainingProps) { + const exampleCount = status?.training_examples_count || 0 + const progressPct = Math.min(100, (exampleCount / 10) * 100) + + return ( +
+ {/* Training Overview */} + + +
+ {/* Add Training Example */} + + + {/* Fine-Tuning */} + +
+ + {/* Training Examples List */} + {examples.length > 0 && ( + + )} + + {/* Training Dashboard Demo */} + +
+ ) +} + +/* ------------------------------------------------------------------ */ + +function TrainingOverviewCard({ + status, + settings, + exampleCount, + progressPct, +}: { + status: TrOCRStatus | null + settings: MagicSettings + exampleCount: number + progressPct: number +}) { + return ( +
+

Training mit LoRA

+

+ LoRA (Low-Rank Adaptation) ermoeglicht effizientes Fine-Tuning ohne das Basismodell zu veraendern. + Das Training erfolgt lokal auf Ihrem System. +

+ +
+
+
{exampleCount}
+
Trainingsbeispiele
+
+
+
10
+
Minimum benoetigt
+
+
+
{settings.loraRank}
+
LoRA Rank
+
+
+
{status?.has_lora_adapter ? '\u2713' : '\u2717'}
+
Adapter aktiv
+
+
+ +
+
+ Fortschritt zum Fine-Tuning + {progressPct.toFixed(0)}% +
+
+
+
+
+
+ ) +} + +function AddExampleCard({ + trainingImage, + trainingText, + onSetTrainingImage, + onSetTrainingText, + onAddExample, +}: { + trainingImage: File | null + trainingText: string + onSetTrainingImage: (file: File | null) => void + onSetTrainingText: (text: string) => void + onAddExample: () => void +}) { + return ( +
+

Trainingsbeispiel hinzufuegen

+

+ Lade ein Bild mit handgeschriebenem Text hoch und gib die korrekte Transkription ein. +

+ +
+
+ + onSetTrainingImage(e.target.files?.[0] || null)} + /> + {trainingImage && ( +
+ Bild ausgewaehlt: {trainingImage.name} +
+ )} +
+
+ +