[split-required] Split 700-870 LOC files across all services

backend-lehrer (11 files):
- llm_gateway/routes/schools.py (867 → 5), recording_api.py (848 → 6)
- messenger_api.py (840 → 5), print_generator.py (824 → 5)
- unit_analytics_api.py (751 → 5), classroom/routes/context.py (726 → 4)
- llm_gateway/routes/edu_search_seeds.py (710 → 4)

klausur-service (12 files):
- ocr_labeling_api.py (845 → 4), metrics_db.py (833 → 4)
- legal_corpus_api.py (790 → 4), page_crop.py (758 → 3)
- mail/ai_service.py (747 → 4), github_crawler.py (767 → 3)
- trocr_service.py (730 → 4), full_compliance_pipeline.py (723 → 4)
- dsfa_rag_api.py (715 → 4), ocr_pipeline_auto.py (705 → 4)

website (6 pages):
- audit-checklist (867 → 8), content (806 → 6)
- screen-flow (790 → 4), scraper (789 → 5)
- zeugnisse (776 → 5), modules (745 → 4)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-25 08:01:18 +02:00
parent b6983ab1dc
commit 34da9f4cda
106 changed files with 16500 additions and 16947 deletions

View File

@@ -0,0 +1,187 @@
"""
Recording API - Meeting Minutes Routes.
Generate, retrieve, and export KI-based meeting minutes.
"""
from datetime import datetime
from typing import Optional
from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import PlainTextResponse, HTMLResponse
from recording_helpers import (
_recordings_store,
_transcriptions_store,
_minutes_store,
log_audit,
)
router = APIRouter(tags=["Recordings"])
# ==========================================
# MEETING MINUTES ENDPOINTS
# ==========================================
@router.post("/{recording_id}/minutes")
async def generate_meeting_minutes(
recording_id: str,
title: Optional[str] = Query(None, description="Meeting-Titel"),
model: str = Query("breakpilot-teacher-8b", description="LLM Modell")
):
"""
Generiert KI-basierte Meeting Minutes aus der Transkription.
Nutzt das LLM Gateway (Ollama/vLLM) fuer lokale Verarbeitung.
"""
from meeting_minutes_generator import get_minutes_generator, MeetingMinutes
# Check recording exists
recording = _recordings_store.get(recording_id)
if not recording:
raise HTTPException(status_code=404, detail="Recording not found")
# Check transcription exists and is completed
transcription = next(
(t for t in _transcriptions_store.values() if t["recording_id"] == recording_id),
None
)
if not transcription:
raise HTTPException(status_code=400, detail="No transcription found. Please transcribe first.")
if transcription["status"] != "completed":
raise HTTPException(
status_code=400,
detail=f"Transcription not ready. Status: {transcription['status']}"
)
# Check if minutes already exist
existing = _minutes_store.get(recording_id)
if existing and existing.get("status") == "completed":
# Return existing minutes
return existing
# Get transcript text
transcript_text = transcription.get("full_text", "")
if not transcript_text:
raise HTTPException(status_code=400, detail="Transcription has no text content")
# Generate meeting minutes
generator = get_minutes_generator()
try:
minutes = await generator.generate(
transcript=transcript_text,
recording_id=recording_id,
transcription_id=transcription["id"],
title=title,
date=recording.get("recorded_at", "")[:10] if recording.get("recorded_at") else None,
duration_minutes=recording.get("duration_seconds", 0) // 60 if recording.get("duration_seconds") else None,
participant_count=recording.get("participant_count", 0),
model=model
)
# Store minutes
minutes_dict = minutes.model_dump()
minutes_dict["generated_at"] = minutes.generated_at.isoformat()
_minutes_store[recording_id] = minutes_dict
# Log action
log_audit(
action="minutes_generated",
recording_id=recording_id,
metadata={"model": model, "generation_time": minutes.generation_time_seconds}
)
return minutes_dict
except Exception as e:
raise HTTPException(status_code=500, detail=f"Minutes generation failed: {str(e)}")
@router.get("/{recording_id}/minutes")
async def get_meeting_minutes(recording_id: str):
"""
Ruft generierte Meeting Minutes ab.
"""
minutes = _minutes_store.get(recording_id)
if not minutes:
raise HTTPException(status_code=404, detail="No meeting minutes found. Generate them first with POST.")
return minutes
def _load_minutes(recording_id: str):
"""Load and convert stored minutes dict back to MeetingMinutes."""
from meeting_minutes_generator import MeetingMinutes
minutes_dict = _minutes_store.get(recording_id)
if not minutes_dict:
raise HTTPException(status_code=404, detail="No meeting minutes found")
minutes_dict_copy = minutes_dict.copy()
if isinstance(minutes_dict_copy.get("generated_at"), str):
minutes_dict_copy["generated_at"] = datetime.fromisoformat(minutes_dict_copy["generated_at"])
return MeetingMinutes(**minutes_dict_copy)
@router.get("/{recording_id}/minutes/markdown")
async def get_minutes_markdown(recording_id: str):
"""
Exportiert Meeting Minutes als Markdown.
"""
from meeting_minutes_generator import minutes_to_markdown
minutes = _load_minutes(recording_id)
markdown = minutes_to_markdown(minutes)
return PlainTextResponse(
content=markdown,
media_type="text/markdown",
headers={"Content-Disposition": f"attachment; filename=protokoll_{recording_id}.md"}
)
@router.get("/{recording_id}/minutes/html")
async def get_minutes_html(recording_id: str):
"""
Exportiert Meeting Minutes als HTML.
"""
from meeting_minutes_generator import minutes_to_html
minutes = _load_minutes(recording_id)
html = minutes_to_html(minutes)
return HTMLResponse(content=html)
@router.get("/{recording_id}/minutes/pdf")
async def get_minutes_pdf(recording_id: str):
"""
Exportiert Meeting Minutes als PDF.
Benoetigt WeasyPrint (pip install weasyprint).
"""
from meeting_minutes_generator import minutes_to_html
minutes = _load_minutes(recording_id)
html = minutes_to_html(minutes)
try:
from weasyprint import HTML
from fastapi.responses import Response
pdf_bytes = HTML(string=html).write_pdf()
return Response(
content=pdf_bytes,
media_type="application/pdf",
headers={"Content-Disposition": f"attachment; filename=protokoll_{recording_id}.pdf"}
)
except ImportError:
raise HTTPException(
status_code=501,
detail="PDF export not available. Install weasyprint: pip install weasyprint"
)