Projektarbeit-MYP/backend/app/create_presentation_enhanced.py
Till Tomczak 736f2fae4c fix: Update documentation in SUMMARY.md for kiosk mode enhancements
- Revised the Kiosk-Mode section in SUMMARY.md to include recent changes related to SSL support and improved user experience.
- Clarified instructions for setting up kiosk mode with the new SSL configuration.
- Ensured consistency in formatting and alignment for better readability.
2025-05-25 21:43:14 +02:00

587 lines
18 KiB
Python

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}")