import os import io import requests from PIL import Image from pptx import Presentation from pptx.util import Inches, Pt from pptx.dml.color import RGBColor from pptx.enum.text import PP_ALIGN # Stile und Konstanten TITLE_FONT = 'Helvetica Neue' BODY_FONT = 'Helvetica Neue' PRIMARY_COLOR = RGBColor(0, 122, 255) # Apple Blau SECONDARY_COLOR = RGBColor(88, 86, 214) # Apple Lila ACCENT_COLOR = RGBColor(255, 149, 0) # Apple Orange DARK_TEXT = RGBColor(50, 50, 50) LIGHT_TEXT = RGBColor(240, 240, 240) BACKGROUND_COLOR = RGBColor(250, 250, 250) SLIDE_WIDTH = Inches(13.333) SLIDE_HEIGHT = Inches(7.5) # Ausgabepfad output_dir = os.path.dirname(os.path.abspath(__file__)) output_path = os.path.join(output_dir, 'MYP_Backend_Schulung_Enhanced.pptx') images_dir = os.path.join(output_dir, 'presentation_images') # Verzeichnis für Bilder erstellen, falls es nicht existiert os.makedirs(images_dir, exist_ok=True) # Funktion zum Herunterladen von Stock-Bildern (nur Beispiel, Sie können auch eigene Bilder verwenden) def download_stock_image(url, filename): try: image_path = os.path.join(images_dir, filename) # Wenn das Bild bereits existiert, nicht erneut herunterladen if os.path.exists(image_path): return image_path response = requests.get(url, stream=True) if response.status_code == 200: with open(image_path, 'wb') as f: f.write(response.content) return image_path else: print(f"Fehler beim Herunterladen des Bildes: {response.status_code}") return None except Exception as e: print(f"Fehler: {e}") return None # Platzhalterbilder für die Präsentation # Im echten Einsatz würden Sie eigene Bilder oder lizenzfreie Bilder verwenden image_urls = { "header": "https://cdn.pixabay.com/photo/2017/08/10/02/05/tiles-shapes-2617112_1280.jpg", "3d_printer": "https://cdn.pixabay.com/photo/2019/07/06/11/15/3d-printer-4320296_1280.jpg", "backend": "https://cdn.pixabay.com/photo/2016/11/27/21/42/stock-1863880_1280.jpg", "database": "https://cdn.pixabay.com/photo/2017/06/14/16/20/network-2402637_1280.jpg", "api": "https://cdn.pixabay.com/photo/2018/05/04/20/01/website-3374825_1280.jpg", "scheduler": "https://cdn.pixabay.com/photo/2018/01/17/07/06/laptop-3087585_1280.jpg", "security": "https://cdn.pixabay.com/photo/2017/11/19/23/56/cyber-security-2965030_1280.jpg", "summary": "https://cdn.pixabay.com/photo/2019/04/14/10/27/book-4126483_1280.jpg" } # Bilder herunterladen image_paths = {} for key, url in image_urls.items(): filename = f"{key}.jpg" image_path = download_stock_image(url, filename) if image_path: image_paths[key] = image_path else: print(f"Konnte Bild {key} nicht herunterladen") # Neue Präsentation erstellen prs = Presentation() # Foliengröße auf 16:9 setzen prs.slide_width = SLIDE_WIDTH prs.slide_height = SLIDE_HEIGHT # Hilfsfunktion für einheitliche Formatierung def apply_text_style(paragraph, font_size, bold=False, color=DARK_TEXT, alignment=PP_ALIGN.LEFT): paragraph.alignment = alignment run = paragraph.runs[0] run.font.name = BODY_FONT run.font.size = Pt(font_size) run.font.bold = bold run.font.color.rgb = color # Hilfsfunktion zum Hinzufügen eines Bildes zu einer Folie def add_image_to_slide(slide, image_path, left, top, width, height=None, keep_ratio=True): if not os.path.exists(image_path): print(f"Bildpfad existiert nicht: {image_path}") return None img = Image.open(image_path) width_inches = width if keep_ratio and height is None: # Seitenverhältnis beibehalten img_ratio = img.height / img.width height_inches = width_inches * img_ratio else: height_inches = height return slide.shapes.add_picture(image_path, left, top, width=width_inches, height=height_inches) # Hilfsfunktion zum Erstellen eines abgerundeten Farbbereichs (als Ersatz für abgerundete Rechtecke) def add_rectangle_to_slide(slide, left, top, width, height, color=PRIMARY_COLOR): shape = slide.shapes.add_shape(1, left, top, width, height) # 1 = Rechteck shape.fill.solid() shape.fill.fore_color.rgb = color shape.line.fill.solid() shape.line.fill.fore_color.rgb = color return shape # ------------- FOLIE 1: TITELFOLIE ------------- slide_layout = prs.slide_layouts[0] # Titelfolie slide = prs.slides.add_slide(slide_layout) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR # Hintergrundbild (wenn verfügbar) if "header" in image_paths: header_img = add_image_to_slide(slide, image_paths["header"], Inches(0), Inches(0), SLIDE_WIDTH, SLIDE_HEIGHT, keep_ratio=False) # Bild in den Hintergrund if header_img: header_img.z_order = 0 # Halbtransparentes Overlay overlay = add_rectangle_to_slide(slide, Inches(0), Inches(0), SLIDE_WIDTH, SLIDE_HEIGHT, RGBColor(0, 0, 0)) overlay.fill.transparency = 0.4 # 40% Transparenz overlay.z_order = 1 # Titel hinzufügen title_shape = slide.shapes.title title_shape.text = "MYP Platform" title_paragraph = title_shape.text_frame.paragraphs[0] apply_text_style(title_paragraph, 64, bold=True, color=LIGHT_TEXT, alignment=PP_ALIGN.CENTER) title_shape.z_order = 2 # Untertitel hinzufügen subtitle_shape = slide.placeholders[1] subtitle_shape.text = "3D-Drucker Reservierungssystem\nBackend-Schulung" subtitle_paragraph = subtitle_shape.text_frame.paragraphs[0] apply_text_style(subtitle_paragraph, 36, color=LIGHT_TEXT, alignment=PP_ALIGN.CENTER) subtitle_shape.z_order = 2 # ------------- FOLIE 2: ÜBERBLICK ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "Systemüberblick" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• Reservierungssystem für 3D-Drucker" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Automatische Steuerung von Smart Plugs" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Echtzeit-Überwachung von Druckaufträgen" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Administrationsfunktionen" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Statistik und Analyse" apply_text_style(p, 28) # Bild einfügen (wenn verfügbar) if "3d_printer" in image_paths: printer_img = add_image_to_slide(slide, image_paths["3d_printer"], Inches(7), Inches(2), Inches(5)) # ------------- FOLIE 3: TECHNOLOGIE-STACK ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "Technologie-Stack" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• Backend: Python 3.11 mit Flask" apply_text_style(p, 28) p.runs[0].font.color.rgb = SECONDARY_COLOR p = tf.add_paragraph() p.text = "• Frontend: HTML/CSS/JavaScript mit Tailwind CSS" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Datenbank: SQLite mit SQLAlchemy ORM" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR p = tf.add_paragraph() p.text = "• Authentifizierung: Flask-Login" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Hardware-Integration: PyP110 für Tapo Smart Plug Steuerung" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Automatisierung: Integrierter Job-Scheduler" apply_text_style(p, 28) # Bild einfügen (wenn verfügbar) if "backend" in image_paths: backend_img = add_image_to_slide(slide, image_paths["backend"], Inches(7), Inches(2), Inches(5)) # ------------- FOLIE 4: ARCHITEKTUR ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "Backend-Architektur" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• Flask-App: Zentrale Anwendungslogik" apply_text_style(p, 28) p.runs[0].font.color.rgb = PRIMARY_COLOR p = tf.add_paragraph() p.text = "• Blueprints: Modulare Strukturierung (auth, user, kiosk)" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Models: SQLAlchemy ORM für Datenbankkommunikation" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR p = tf.add_paragraph() p.text = "• Utils: Job-Scheduler, Logging, Template-Helpers" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• API: RESTful-Endpunkte für Frontend-Kommunikation" apply_text_style(p, 28) p.runs[0].font.color.rgb = SECONDARY_COLOR # ------------- FOLIE 5: DATENMODELL ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "Datenmodell" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• User: Benutzer mit Rollen und Authentifizierung" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Printer: 3D-Drucker mit Smart-Plug-Konfigurationen" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR p = tf.add_paragraph() p.text = "• Job: Druckaufträge mit Status und Zeitplanung" apply_text_style(p, 28) p.runs[0].font.color.rgb = SECONDARY_COLOR p = tf.add_paragraph() p.text = "• Stats: Systemstatistiken und Metriken" apply_text_style(p, 28) # Bild einfügen (wenn verfügbar) if "database" in image_paths: db_img = add_image_to_slide(slide, image_paths["database"], Inches(7), Inches(2), Inches(5)) # ------------- FOLIE 6: API-ENDPUNKTE ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "API-Endpunkte" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• /api/jobs: Druckaufträge verwalten" apply_text_style(p, 28) p.runs[0].font.color.rgb = SECONDARY_COLOR p = tf.add_paragraph() p.text = "• /api/printers: Drucker verwalten" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR p = tf.add_paragraph() p.text = "• /api/users: Benutzer verwalten" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• /api/stats: Statistiken abrufen" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• /api/scheduler: Scheduler steuern" apply_text_style(p, 28) p.runs[0].font.color.rgb = PRIMARY_COLOR # Bild einfügen (wenn verfügbar) if "api" in image_paths: api_img = add_image_to_slide(slide, image_paths["api"], Inches(7), Inches(2), Inches(5)) # ------------- FOLIE 7: JOB-SCHEDULER ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "Job-Scheduler" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• Automatische Steuerung der Drucker" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Einschalten bei Auftragsstart" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR p = tf.add_paragraph() p.text = "• Ausschalten bei Auftragsende" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR p = tf.add_paragraph() p.text = "• Statusüberwachung und -aktualisierung" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Sammeln von Statistiken" apply_text_style(p, 28) # Bild einfügen (wenn verfügbar) if "scheduler" in image_paths: scheduler_img = add_image_to_slide(slide, image_paths["scheduler"], Inches(7), Inches(2), Inches(5)) # ------------- FOLIE 8: LOGGING-SYSTEM ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "Logging-System" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• Separate Logs für verschiedene Bereiche:" apply_text_style(p, 28) p.runs[0].font.bold = True p = tf.add_paragraph() p.text = " - App-Logs: Allgemeine Anwendungslogs" apply_text_style(p, 28) p = tf.add_paragraph() p.text = " - Auth-Logs: Authentifizierungsereignisse" apply_text_style(p, 28) p = tf.add_paragraph() p.text = " - Job-Logs: Druckauftragsoperationen" apply_text_style(p, 28) p.runs[0].font.color.rgb = SECONDARY_COLOR p = tf.add_paragraph() p.text = " - Printer-Logs: Druckerstatusänderungen" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR p = tf.add_paragraph() p.text = " - Scheduler-Logs: Automatisierungsaktionen" apply_text_style(p, 28) # ------------- FOLIE 9: SICHERHEITSKONZEPT ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "Sicherheitskonzept" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• Benutzerauthentifizierung mit bcrypt" apply_text_style(p, 28) p.runs[0].font.color.rgb = SECONDARY_COLOR p = tf.add_paragraph() p.text = "• Rollenbasierte Zugriffskontrolle" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• CSRF-Schutz bei Formularen" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Besitzer-Check für Druckaufträge" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR p = tf.add_paragraph() p.text = "• Sichere HTTP-Header" apply_text_style(p, 28) # Bild einfügen (wenn verfügbar) if "security" in image_paths: security_img = add_image_to_slide(slide, image_paths["security"], Inches(7), Inches(2), Inches(5)) # ------------- FOLIE 10: ZUSAMMENFASSUNG ------------- slide = prs.slides.add_slide(prs.slide_layouts[1]) # Hintergrund anpassen background = slide.background fill = background.fill fill.solid() fill.fore_color.rgb = BACKGROUND_COLOR title = slide.shapes.title title.text = "Zusammenfassung" title_paragraph = title.text_frame.paragraphs[0] apply_text_style(title_paragraph, 44, bold=True, color=PRIMARY_COLOR, alignment=PP_ALIGN.LEFT) # Inhalt content = slide.placeholders[1] tf = content.text_frame p = tf.paragraphs[0] p.text = "• Vollständige Lösung für 3D-Drucker-Management" apply_text_style(p, 28) p.runs[0].font.bold = True p = tf.add_paragraph() p.text = "• Modulare Architektur für einfache Erweiterbarkeit" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Robuste Sicherheitskonzepte" apply_text_style(p, 28) p.runs[0].font.color.rgb = SECONDARY_COLOR p = tf.add_paragraph() p.text = "• Umfassendes Logging und Überwachung" apply_text_style(p, 28) p = tf.add_paragraph() p.text = "• Automatisierung von Routineaufgaben" apply_text_style(p, 28) p.runs[0].font.color.rgb = ACCENT_COLOR # Bild einfügen (wenn verfügbar) if "summary" in image_paths: summary_img = add_image_to_slide(slide, image_paths["summary"], Inches(7), Inches(2), Inches(5)) # Präsentation speichern prs.save(output_path) print(f"Verbesserte Präsentation wurde erstellt: {output_path}")