""" AI Processing - Print Version Generator: Worksheet. Generates print-optimized HTML for general worksheets from analysis data. """ from pathlib import Path import json import logging logger = logging.getLogger(__name__) def generate_print_version_worksheet(analysis_path: Path) -> str: """ Generiert eine druckoptimierte HTML-Version des Arbeitsblatts. Eigenschaften: - Grosse, gut lesbare Schrift (16pt) - Schwarz-weiss / Graustufen-tauglich - Klare Struktur fuer Druck - Keine interaktiven Elemente Args: analysis_path: Pfad zur *_analyse.json Datei Returns: HTML-String zum direkten Ausliefern """ if not analysis_path.exists(): raise FileNotFoundError(f"Analysedatei nicht gefunden: {analysis_path}") try: data = json.loads(analysis_path.read_text(encoding="utf-8")) except json.JSONDecodeError as e: raise RuntimeError(f"Analyse-Datei enthaelt kein gueltiges JSON: {analysis_path}\n{e}") from e title = data.get("title") or "Arbeitsblatt" subject = data.get("subject") or "" grade_level = data.get("grade_level") or "" instructions = data.get("instructions") or "" tasks = data.get("tasks", []) or [] canonical_text = data.get("canonical_text") or "" printed_blocks = data.get("printed_blocks") or [] html_parts = [] html_parts.append(_build_html_head(title)) # Titel html_parts.append(f"

{title}

") # Meta-Informationen meta_parts = [] if subject: meta_parts.append(f"Fach: {subject}") if grade_level: meta_parts.append(f"Klasse: {grade_level}") if meta_parts: html_parts.append(f"
{''.join(meta_parts)}
") # Arbeitsanweisung if instructions: html_parts.append("
") html_parts.append("
Arbeitsanweisung:
") html_parts.append(f"
{instructions}
") html_parts.append("
") # Haupttext / gedruckte Bloecke _build_text_section(html_parts, printed_blocks, canonical_text) # Aufgaben _build_tasks_section(html_parts, tasks) # Fusszeile html_parts.append("") html_parts.append("") return "\n".join(html_parts) def _build_html_head(title: str) -> str: """Build the HTML head with print-optimized styles.""" return """ """ + title + """ """ def _build_text_section(html_parts: list, printed_blocks: list, canonical_text: str): """Build the text section from printed blocks or canonical text.""" if printed_blocks: html_parts.append("
") for block in printed_blocks: role = (block.get("role") or "body").lower() text = (block.get("text") or "").strip() if not text: continue if role == "title": html_parts.append(f"
{text}
") else: html_parts.append(f"
{text}
") html_parts.append("
") elif canonical_text: html_parts.append("
") paragraphs = [ p.strip() for p in canonical_text.replace("\r\n", "\n").split("\n\n") if p.strip() ] for p in paragraphs: html_parts.append(f"
{p}
") html_parts.append("
") def _build_tasks_section(html_parts: list, tasks: list): """Build the tasks section.""" if not tasks: return html_parts.append("
") html_parts.append("

Aufgaben

") type_labels = { "fill_in_blank": "Lueckentext", "multiple_choice": "Multiple Choice", "free_text": "Freitext", "matching": "Zuordnung", "labeling": "Beschriftung", "calculation": "Rechnung", "other": "Aufgabe" } for idx, task in enumerate(tasks, start=1): t_type = task.get("type") or "Aufgabe" desc = task.get("description") or "" text_with_gaps = task.get("text_with_gaps") html_parts.append("
") type_label = type_labels.get(t_type, t_type) html_parts.append(f"
Aufgabe {idx}: {type_label}
") if desc: html_parts.append(f"
{desc}
") if text_with_gaps: rendered = text_with_gaps.replace("___", " ") html_parts.append(f"
{rendered}
") # Antwortlinien fuer Freitext-Aufgaben if t_type in ["free_text", "other"] or (not text_with_gaps and not desc): html_parts.append("
") for _ in range(3): html_parts.append("
") html_parts.append("
") html_parts.append("
") html_parts.append("
")