HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //workspace/montessori_redesign.py
#!/usr/bin/env python3
"""Montessori-Redesign für FOS Deutsch Arbeitsblätter"""

from docx import Document
from docx.shared import Pt, RGBColor, Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import os
import re

COLORS = {
    'dunkel_grau': RGBColor(70, 70, 70),
    'mittel_grau': RGBColor(100, 100, 100),
}

def set_cell_shading(cell, color_hex):
    shading_elm = OxmlElement('w:shd')
    shading_elm.set(qn('w:fill'), color_hex)
    cell._tc.get_or_add_tcPr().append(shading_elm)

def set_cell_border(cell, top=None, bottom=None, left=None, right=None):
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()
    tcBorders = OxmlElement('w:tcBorders')
    
    for edge, data in [('top', top), ('bottom', bottom), ('left', left), ('right', right)]:
        if data:
            tag = OxmlElement(f'w:{edge}')
            tag.set(qn('w:val'), data.get('val', 'single'))
            tag.set(qn('w:sz'), str(data.get('sz', 4)))
            tag.set(qn('w:color'), data.get('color', '808080'))
            tcBorders.append(tag)
    
    tcPr.append(tcBorders)

def create_header(doc, title, themenbereich=None, kompetenz=None):
    """Erstellt eleganten Header-Bereich"""
    table = doc.add_table(rows=1, cols=1)
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    cell = table.cell(0, 0)
    set_cell_shading(cell, 'FAF7F0')
    
    # Titel
    p = cell.paragraphs[0]
    run = p.add_run(title)
    run.bold = True
    run.font.size = Pt(16)
    run.font.color.rgb = COLORS['dunkel_grau']
    p.paragraph_format.space_after = Pt(8)
    
    # Trennlinie
    p_line = cell.add_paragraph()
    pPr = p_line._p.get_or_add_pPr()
    pBdr = OxmlElement('w:pBdr')
    bottom = OxmlElement('w:bottom')
    bottom.set(qn('w:val'), 'single')
    bottom.set(qn('w:sz'), '6')
    bottom.set(qn('w:color'), 'C4A491')
    pBdr.append(bottom)
    pPr.append(pBdr)
    
    # Info
    if themenbereich or kompetenz:
        p_info = cell.add_paragraph()
        p_info.paragraph_format.space_before = Pt(6)
        if themenbereich:
            run = p_info.add_run(f"Themenbereich: {themenbereich}\n")
            run.italic = True
            run.font.size = Pt(9)
            run.font.color.rgb = COLORS['mittel_grau']
        if kompetenz:
            run = p_info.add_run(f"Kompetenz: {kompetenz}")
            run.italic = True
            run.font.size = Pt(9)
            run.font.color.rgb = COLORS['mittel_grau']
    
    # Rahmen
    set_cell_border(cell,
                   top={'sz': 16, 'color': 'C4A491'},
                   bottom={'sz': 8, 'color': 'C3D2C3'},
                   left={'sz': 4, 'color': 'A0A0A0'},
                   right={'sz': 4, 'color': 'A0A0A0'})
    
    doc.add_paragraph()
    return table

def create_box(doc, title, content_lines, box_type='aufgabe'):
    """Erstellt gestaltete Box"""
    table = doc.add_table(rows=1, cols=1)
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    cell = table.cell(0, 0)
    
    # Farbe je nach Typ
    color_map = {
        'aufgabe': 'F2EBDC',      # Sand
        'material': 'C3D2C3',    # Salbei
        'reflexion': 'B0BCB8',   # Blau
    }
    set_cell_shading(cell, color_map.get(box_type, 'F2EBDC'))
    
    if title:
        p = cell.paragraphs[0]
        run = p.add_run(title)
        run.bold = True
        run.font.size = Pt(11)
        run.font.color.rgb = COLORS['dunkel_grau']
        p.paragraph_format.space_after = Pt(8)
        
        for line in content_lines:
            p = cell.add_paragraph()
            p.paragraph_format.space_before = Pt(2)
            p.paragraph_format.space_after = Pt(2)
            run = p.add_run(line)
            run.font.size = Pt(10)
            run.font.color.rgb = COLORS['dunkel_grau']
    
    # Rahmen
    set_cell_border(cell,
                   top={'sz': 12, 'color': 'A0A0A0'},
                   bottom={'sz': 12, 'color': 'A0A0A0'},
                   left={'sz': 12, 'color': 'A0A0A0'},
                   right={'sz': 12, 'color': 'A0A0A0'})
    
    doc.add_paragraph()
    return table

def create_image_placeholder(doc, caption):
    """Erstellt Bild-Platzhalter"""
    table = doc.add_table(rows=2, cols=1)
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    
    # Bildbereich
    img_cell = table.cell(0, 0)
    set_cell_shading(img_cell, 'F2EBDC')
    p = img_cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = p.add_run(f"[Bild: {caption}]")
    run.font.size = Pt(11)
    run.font.color.rgb = COLORS['mittel_grau']
    p.paragraph_format.space_before = Pt(20)
    p.paragraph_format.space_after = Pt(20)
    
    # Beschriftung
    cap_cell = table.cell(1, 0)
    set_cell_shading(cap_cell, 'FAF7F0')
    p = cap_cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = p.add_run(caption)
    run.italic = True
    run.font.size = Pt(9)
    run.font.color.rgb = COLORS['mittel_grau']
    
    for cell in [img_cell, cap_cell]:
        set_cell_border(cell,
                       top={'sz': 8, 'color': 'C3D2C3'},
                       bottom={'sz': 8, 'color': 'C3D2C3'},
                       left={'sz': 8, 'color': 'C3D2C3'},
                       right={'sz': 8, 'color': 'C3D2C3'})
    
    doc.add_paragraph()
    return table

def redesign_ab(input_path, output_path, illustration=None):
    """Redesign eines Arbeitsblatts"""
    print(f"Verarbeite: {os.path.basename(input_path)}")
    
    doc_orig = Document(input_path)
    doc = Document()
    
    # Seite einrichten
    for section in doc.sections:
        section.page_width = Cm(21)
        section.page_height = Cm(29.7)
        section.left_margin = Cm(2.5)
        section.right_margin = Cm(2.5)
        section.top_margin = Cm(2)
        section.bottom_margin = Cm(2)
    
    # Inhalt extrahieren
    title = None
    themenbereich = None
    kompetenz = None
    aufgaben = []
    current_aufgabe = None
    lehrerhinweise = []
    
    for para in doc_orig.paragraphs:
        text = para.text.strip()
        if not text:
            continue
        
        style = para.style.name if para.style else 'Normal'
        
        if style == 'Heading 1' and not title:
            title = text
            continue
        
        if text.startswith('Themenbereich:'):
            themenbereich = text.replace('Themenbereich:', '').strip()
            continue
        if text.startswith('Kompetenz:'):
            kompetenz = text.replace('Kompetenz:', '').strip()
            continue
        
        if 'Illustration' in text or 'Abbildung:' in text:
            if not illustration:
                # Extrahiere Illustrationsnamen
                match = re.search(r'(VK|JG\d{2})[_\s](.+?)\s*(?:Illustration|$)', text, re.I)
                if match:
                    illustration = match.group(0).replace('Abbildung: ', '').strip()
            continue
        
        if text.startswith('===') or text.startswith('---'):
            continue
        
        if text == 'Lehrerhinweise:':
            current_aufgabe = 'lehrer'
            continue
        
        if current_aufgabe == 'lehrer':
            lehrerhinweise.append(text)
            continue
        
        if style == 'Heading 2':
            if current_aufgabe and current_aufgabe != 'lehrer':
                aufgaben.append(current_aufgabe)
            current_aufgabe = {'titel': text, 'inhalt': []}
            continue
        
        if current_aufgabe and isinstance(current_aufgabe, dict):
            if not text.startswith('___'):
                current_aufgabe['inhalt'].append(text)
    
    if current_aufgabe and isinstance(current_aufgabe, dict):
        aufgaben.append(current_aufgabe)
    
    # NEUES DOKUMENT AUFBAUEN
    if title:
        create_header(doc, title, themenbereich, kompetenz)
    
    # Bild OBEN
    if illustration:
        create_image_placeholder(doc, illustration)
    
    # Aufgaben
    for i, aufgabe in enumerate(aufgaben):
        if isinstance(aufgabe, dict):
            box_type = 'material' if i == 0 else 'aufgabe'
            create_box(doc, aufgabe['titel'], aufgabe['inhalt'], box_type)
    
    # Reflexion
    p = doc.add_paragraph()
    run = p.add_run("Reflexion")
    run.bold = True
    run.font.size = Pt(12)
    run.font.color.rgb = COLORS['dunkel_grau']
    
    create_box(doc, None, [
        "Was hast du bei dieser Einheit gelernt?",
        "Welche Fragen sind noch offen geblieben?"
    ], 'reflexion')
    
    # Lehrerhinweise
    if lehrerhinweise:
        p = doc.add_paragraph()
        p.paragraph_format.space_before = Pt(12)
        
        p = doc.add_paragraph()
        run = p.add_run("Hinweise für Lehrkräfte")
        run.bold = True
        run.font.size = Pt(9)
        run.font.color.rgb = COLORS['mittel_grau']
        
        for hinweis in lehrerhinweise[:3]:
            p = doc.add_paragraph()
            run = p.add_run(f"• {hinweis[:150]}")
            run.font.size = Pt(8)
            run.font.color.rgb = COLORS['mittel_grau']
    
    doc.save(output_path)
    print(f"  ✓ Gespeichert: {os.path.basename(output_path)}")
    return True

def find_illustration(filename, prefix):
    """Findet passende Illustration"""
    mapping = {
        'VK': {
            'KI-gestützt': 'VK_KI-Schreiben_Illustration',
            'Digitale': 'VK_Digitale-Texte_Illustration',
            'Feedback': 'VK_Funktion1_Einstieg',
        },
        'JG11': {
            'Social': 'JG11_Social-Media_Illustration',
            'KI-gestütztes': 'JG11_Funktion1_Einstieg',
            'Podcast': 'JG11_Podcast-Medien_Illustration',
        },
        'JG12': {
            'Desinformation': 'JG12_Medienmanipulation_Analyse',
            'Framing': 'JG12_Framing_Perspektiven',
            'KI_gestütztes': 'JG12_Funktion1_Einstieg',
        },
        'JG13': {
            'Data': 'JG13_Data_Bias_Algorithmen',
            'Wissenschaft': 'JG13_Funktion1_Einstieg',
            'Mensch': 'JG13_Mensch_vs_KI_Kreativitaet',
        }
    }
    
    for keyword, illus in mapping.get(prefix, {}).items():
        if keyword.lower() in filename.lower():
            return illus
    return None

def main():
    base = "/mnt/onedrive_write/FOS_Deutsch_Lehrplanvergleich_2026"
    
    jahrgaenge = [
        ('02_Vorklasse/Arbeitsblaetter', 'VK'),
        ('03_Jahrgang_11/Arbeitsblätter', 'JG11'),
        ('04_Jahrgang_12/Arbeitsblätter', 'JG12'),
        ('05_Jahrgang_13/Arbeitsblätter', 'JG13'),
    ]
    
    print("=" * 60)
    print("REDESIGN: FOS Deutsch → Montessori-Stil")
    print("=" * 60)
    
    done = []
    errors = []
    
    for ordner, prefix in jahrgaenge:
        path = os.path.join(base, ordner)
        if not os.path.exists(path):
            continue
        
        for filename in os.listdir(path):
            if not filename.endswith('.docx'):
                continue
            if '_Montessori' in filename or '_Redesign' in filename:
                continue
            
            input_file = os.path.join(path, filename)
            
            # Prüfen ob lesbar
            try:
                with open(input_file, 'rb') as f:
                    f.read(100)
            except:
                print(f"  ⚠ Nicht lesbar: {filename}")
                errors.append(filename)
                continue
            
            base_name = filename.replace('.docx', '')
            output_file = os.path.join(path, f"{base_name}_Montessori.docx")
            
            illus = find_illustration(filename, prefix)
            
            try:
                redesign_ab(input_file, output_file, illus)
                done.append({'original': filename, 'neu': f"{base_name}_Montessori.docx", 'illustration': illus})
            except Exception as e:
                print(f"  ✗ Fehler bei {filename}: {e}")
                errors.append(filename)
    
    print("\n" + "=" * 60)
    print(f"Redesigniert: {len(done)} Arbeitsblätter")
    print(f"Fehler: {len(errors)}")
    
    return done, errors

if __name__ == '__main__':
    done, errors = main()