This commit is contained in:
ValueOn AG 2025-10-18 20:16:57 +02:00
parent 1b55b603fe
commit c49a59f46c
11 changed files with 5676 additions and 1433 deletions

File diff suppressed because it is too large Load diff

1230
mandates/bwt/script.html Normal file

File diff suppressed because it is too large Load diff

View file

@ -62,30 +62,30 @@ BWT (Best Water Technology) ist Europas führendes Wastertechnologie-Unternehmen
```
┌─────────────────────────────────────────────────────────────────┐
│ AI SUPPORT SYSTEM
│ AI SUPPORT SYSTEM │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Telefon │────▶│ AI Voice │────▶│ Backend │
│ │ Interface │ │ Assistant │ │ Services │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ Telefon │───> │ AI Voice │────>│ Backend │
│ │ Interface │ │ Assistant │ │ Services │
│ └──────────────┘ └──────────────┘ └──────────────┘
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Triage & │ │ Database │ │
│ │ Routing │ │ (CRM) │ │
│ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐
│ │ Agent UI │◀────────────┤
│ │ Dashboard │ │
│ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐
│ │ Triage & │ │ Database │
│ │ Routing │ │ (CRM) │
│ └──────────────┘ └──────────────┘
| |
│ ┌──────────────┐ |
│ │ Agent UI │<────────────
│ │ Dashboard │
│ └──────────────┘
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Email │ │
│ │ Service │ │
│ └──────────────┘ │
│ ┌──────────────┐
│ │ Email │
│ │ Service │
│ └──────────────┘
└─────────────────────────────────────────────────────────────────┘
```

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

27
templates/convert_md.bat Normal file
View file

@ -0,0 +1,27 @@
@echo off
REM PowerON Markdown to HTML Converter - Windows Batch Script
REM Verwendung: convert_md.bat [markdown-datei] [output-datei]
if "%1"=="" (
echo PowerON Markdown zu HTML Konverter
echo.
echo Verwendung:
echo convert_md.bat document.md
echo convert_md.bat document.md output.html
echo convert_md.bat -d ./docs
echo.
pause
exit /b 1
)
python md_to_html_converter.py %*
if %ERRORLEVEL% EQU 0 (
echo.
echo Konvertierung erfolgreich abgeschlossen!
) else (
echo.
echo Fehler bei der Konvertierung!
)
pause

View file

@ -0,0 +1,660 @@
#!/usr/bin/env python3
"""
PowerON Markdown to HTML Converter
Konvertiert Markdown-Dateien zu HTML mit PowerON-Styling
"""
import os
import sys
import argparse
from pathlib import Path
import re
# Einfache Markdown-zu-HTML Konvertierung ohne externe Abhängigkeiten
def _convert_markdown_to_html(markdown_text):
"""Einfache Markdown-zu-HTML Konvertierung ohne externe Bibliotheken"""
# HTML-Escaping
def escape_html(text):
return (text.replace('&', '&amp;')
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace('"', '&quot;')
.replace("'", '&#x27;'))
# Code-Blöcke zuerst verarbeiten (vor anderen Formatierungen)
def process_code_blocks(text):
# Fenced code blocks (```)
def replace_code_block(match):
language = match.group(1) or ''
code = match.group(2)
return f'<pre><code class="language-{language}">{escape_html(code)}</code></pre>'
text = re.sub(r'```(\w+)?\n(.*?)\n```', replace_code_block, text, flags=re.DOTALL)
# Inline code (`)
text = re.sub(r'`([^`]+)`', r'<code>\1</code>', text)
return text
# Headers
def process_headers(text):
text = re.sub(r'^###### (.*?)$', r'<h6>\1</h6>', text, flags=re.MULTILINE)
text = re.sub(r'^##### (.*?)$', r'<h5>\1</h5>', text, flags=re.MULTILINE)
text = re.sub(r'^#### (.*?)$', r'<h4>\1</h4>', text, flags=re.MULTILINE)
text = re.sub(r'^### (.*?)$', r'<h3>\1</h3>', text, flags=re.MULTILINE)
text = re.sub(r'^## (.*?)$', r'<h2>\1</h2>', text, flags=re.MULTILINE)
text = re.sub(r'^# (.*?)$', r'<h1>\1</h1>', text, flags=re.MULTILINE)
return text
# Listen
def process_lists(text):
lines = text.split('\n')
in_ul = False
in_ol = False
result = []
for line in lines:
# Ungeordnete Listen
if re.match(r'^\s*[-*+]\s+', line):
if in_ol:
result.append('</ol>')
in_ol = False
if not in_ul:
result.append('<ul>')
in_ul = True
item = re.sub(r'^\s*[-*+]\s+', '', line)
result.append(f'<li>{item}</li>')
# Geordnete Listen
elif re.match(r'^\s*\d+\.\s+', line):
if in_ul:
result.append('</ul>')
in_ul = False
if not in_ol:
result.append('<ol>')
in_ol = True
item = re.sub(r'^\s*\d+\.\s+', '', line)
result.append(f'<li>{item}</li>')
else:
if in_ul:
result.append('</ul>')
in_ul = False
if in_ol:
result.append('</ol>')
in_ol = False
result.append(line)
if in_ul:
result.append('</ul>')
if in_ol:
result.append('</ol>')
return '\n'.join(result)
# Links und Bilder
def process_links_and_images(text):
# Bilder ![alt](url)
text = re.sub(r'!\[([^\]]*)\]\(([^)]+)\)', r'<img src="\2" alt="\1">', text)
# Links [text](url)
text = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'<a href="\2">\1</a>', text)
return text
# Bold und Italic
def process_emphasis(text):
# Bold **text**
text = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', text)
# Italic *text*
text = re.sub(r'\*(.*?)\*', r'<em>\1</em>', text)
return text
# Blockquotes
def process_blockquotes(text):
lines = text.split('\n')
in_quote = False
result = []
for line in lines:
if line.strip().startswith('>'):
if not in_quote:
result.append('<blockquote>')
in_quote = True
quote_text = line.strip()[1:].strip()
result.append(f'<p>{quote_text}</p>')
else:
if in_quote:
result.append('</blockquote>')
in_quote = False
result.append(line)
if in_quote:
result.append('</blockquote>')
return '\n'.join(result)
# Tabellen
def process_tables(text):
lines = text.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i].strip()
# Prüfe ob es eine Tabellenzeile ist (enthält |)
if '|' in line and not line.startswith('<'):
table_lines = []
j = i
# Sammle alle aufeinanderfolgenden Tabellenzeilen
while j < len(lines) and '|' in lines[j].strip() and not lines[j].strip().startswith('<'):
table_lines.append(lines[j].strip())
j += 1
if len(table_lines) >= 2: # Mindestens Header + Separator
# Erstelle HTML-Tabelle
table_html = ['<table>']
# Header-Zeile
header_cells = [cell.strip() for cell in table_lines[0].split('|')[1:-1]]
table_html.append('<thead><tr>')
for cell in header_cells:
table_html.append(f'<th>{cell}</th>')
table_html.append('</tr></thead>')
# Separator-Zeile überspringen
if len(table_lines) > 1 and '---' in table_lines[1]:
data_start = 2
else:
data_start = 1
# Daten-Zeilen
if len(table_lines) > data_start:
table_html.append('<tbody>')
for row in table_lines[data_start:]:
if '|' in row:
data_cells = [cell.strip() for cell in row.split('|')[1:-1]]
table_html.append('<tr>')
for cell in data_cells:
table_html.append(f'<td>{cell}</td>')
table_html.append('</tr>')
table_html.append('</tbody>')
table_html.append('</table>')
result.append('\n'.join(table_html))
i = j - 1 # -1 weil i am Ende des Loops erhöht wird
else:
result.append(f'<p>{line}</p>')
else:
result.append(f'<p>{line}</p>')
i += 1
return '\n'.join(result)
# Horizontale Linien
def process_hr(text):
text = re.sub(r'^---$', '<hr>', text, flags=re.MULTILINE)
return text
# Paragraphen - Jeder Zeilenumbruch wird zu einem <p> Tag
def process_paragraphs(text):
lines = text.split('\n')
result = []
for line in lines:
line = line.strip()
if line:
# Nur wenn es nicht schon ein HTML-Tag ist
if not re.match(r'<[h1-6]|<ul|<ol|<blockquote|<pre|<hr|<li|<table|<thead|<tbody|<tr|<th|<td', line):
result.append(f'<p>{line}</p>')
else:
result.append(line)
else:
# Leere Zeilen werden zu leeren <p> Tags
result.append('<p></p>')
return '\n'.join(result)
# Verarbeitung in der richtigen Reihenfolge
text = markdown_text
# Code-Blöcke zuerst (vor anderen Formatierungen)
text = process_code_blocks(text)
# Headers
text = process_headers(text)
# Tabellen
text = process_tables(text)
# Blockquotes
text = process_blockquotes(text)
# Listen
text = process_lists(text)
# Links und Bilder
text = process_links_and_images(text)
# Emphasis
text = process_emphasis(text)
# Horizontale Linien
text = process_hr(text)
# Paragraphen
text = process_paragraphs(text)
return text
class PowerONHTMLConverter:
def __init__(self, css_file="poweron-styles.css"):
self.css_file = css_file
def create_html_template(self, title, content, css_path=None):
"""Erstellt HTML-Template mit PowerON-Styling"""
if css_path is None:
css_path = self.css_file
html_template = f"""<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="/poweron-favicon.png" type="image/png">
<title>{title} | PowerON</title>
<meta name="description" content="PowerON - KI für Unternehmen | {title}">
<meta name="author" content="PowerON">
<!-- Open Graph Meta Tags -->
<meta property="og:title" content="{title} | PowerON">
<meta property="og:description" content="PowerON - KI für Unternehmen | {title}">
<meta property="og:type" content="article">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,wght@0,400;0,500;0,700;1,400&display=swap" rel="stylesheet">
<!-- PowerON Styles -->
<link rel="stylesheet" href="{css_path}">
<!-- Inline CSS als Fallback -->
<style>
/* PowerON Base Styles - Fallback */
body {{
font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #1a1a1a;
background-color: #ffffff;
margin: 0;
padding: 0;
}}
.header {{
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
padding: 1rem 0;
}}
.navbar {{
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}}
.logo {{
font-size: 1.5rem;
font-weight: 700;
color: #1a1a1a;
text-decoration: none;
}}
.footer {{
background: #1a1a1a;
color: white;
padding: 2rem 0;
text-align: center;
margin-top: 4rem;
}}
.container {{
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}}
</style>
<!-- Additional Styles for Markdown Content -->
<style>
/* Markdown Content Styling */
.markdown-content {{
max-width: 800px;
margin: 0 auto;
padding: 2rem;
line-height: 1.7;
}}
.markdown-content h1 {{
border-bottom: 3px solid #4B73FF;
padding-bottom: 0.5rem;
margin-bottom: 2rem;
}}
.markdown-content h2 {{
border-bottom: 2px solid #e5e5e5;
padding-bottom: 0.3rem;
margin-top: 2.5rem;
margin-bottom: 1.5rem;
}}
.markdown-content h3 {{
color: #4B73FF;
margin-top: 2rem;
margin-bottom: 1rem;
}}
.markdown-content h4 {{
color: #6b7280;
margin-top: 1.5rem;
margin-bottom: 0.75rem;
}}
.markdown-content blockquote {{
border-left: 4px solid #4B73FF;
background: #f8fafc;
padding: 1rem 1.5rem;
margin: 1.5rem 0;
border-radius: 0 8px 8px 0;
font-style: italic;
}}
.markdown-content code {{
background: #f1f5f9;
padding: 0.2rem 0.4rem;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
color: #e11d48;
}}
.markdown-content pre {{
background: #1e293b;
color: #e2e8f0;
padding: 1.5rem;
border-radius: 8px;
overflow-x: auto;
margin: 1.5rem 0;
}}
.markdown-content pre code {{
background: none;
padding: 0;
color: inherit;
font-size: 0.9em;
}}
.markdown-content table {{
width: 100%;
border-collapse: collapse;
margin: 1.5rem 0;
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}}
.markdown-content th {{
background: #4B73FF;
color: white;
padding: 1rem;
text-align: left;
font-weight: 600;
}}
.markdown-content td {{
padding: 1rem;
border-bottom: 1px solid #e5e5e5;
}}
.markdown-content tr:hover {{
background: #f8fafc;
}}
.markdown-content ul, .markdown-content ol {{
margin: 1rem 0;
padding-left: 2rem;
}}
.markdown-content li {{
margin: 0.5rem 0;
}}
.markdown-content img {{
max-width: 100%;
height: auto;
border-radius: 8px;
margin: 1.5rem 0;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}}
.markdown-content a {{
color: #4B73FF;
text-decoration: none;
border-bottom: 1px solid transparent;
transition: all 0.3s ease;
}}
.markdown-content a:hover {{
border-bottom-color: #4B73FF;
}}
.markdown-content hr {{
border: none;
height: 2px;
background: linear-gradient(90deg, transparent, #4B73FF, transparent);
margin: 3rem 0;
}}
/* Table of Contents */
.toc {{
background: #f8fafc;
border: 1px solid #e5e5e5;
border-radius: 8px;
padding: 1.5rem;
margin: 2rem 0;
}}
.toc h2 {{
margin-top: 0;
color: #1a1a1a;
border-bottom: 2px solid #4B73FF;
padding-bottom: 0.5rem;
}}
.toc ul {{
list-style: none;
padding-left: 0;
}}
.toc li {{
margin: 0.5rem 0;
}}
.toc a {{
color: #6b7280;
text-decoration: none;
transition: color 0.3s ease;
}}
.toc a:hover {{
color: #4B73FF;
}}
/* Responsive */
@media (max-width: 768px) {{
.markdown-content {{
padding: 1rem;
}}
.markdown-content h1 {{
font-size: 2.5rem;
}}
.markdown-content h2 {{
font-size: 2rem;
}}
.markdown-content h3 {{
font-size: 1.5rem;
}}
}}
</style>
</head>
<body>
<!-- Header -->
<header class="header">
<div class="navbar">
</div>
</header>
<!-- Main Content -->
<main style="margin-top: 80px;">
<div class="markdown-content">
{content}
</div>
</main>
<!-- Footer -->
<footer class="footer">
<div class="container">
<p>&copy; 2024 PowerON - KI für Unternehmen. Alle Rechte vorbehalten.</p>
</div>
</footer>
</body>
</html>"""
return html_template
def convert_markdown_file(self, input_file, output_file=None, css_path=None):
"""Konvertiert eine Markdown-Datei zu HTML"""
input_path = Path(input_file)
if not input_path.exists():
raise FileNotFoundError(f"Markdown-Datei nicht gefunden: {input_file}")
# Output-Datei bestimmen
if output_file is None:
output_file = input_path.with_suffix('.html')
else:
output_file = Path(output_file)
# Markdown lesen und konvertieren
with open(input_path, 'r', encoding='utf-8') as f:
markdown_content = f.read()
# Titel aus Markdown extrahieren (erste H1)
title_match = re.search(r'^#\s+(.+)$', markdown_content, re.MULTILINE)
title = title_match.group(1) if title_match else input_path.stem
# Markdown zu HTML konvertieren
html_content = _convert_markdown_to_html(markdown_content)
# HTML-Template erstellen
full_html = self.create_html_template(title, html_content, css_path)
# HTML-Datei schreiben
with open(output_file, 'w', encoding='utf-8') as f:
f.write(full_html)
print(f"Konvertiert: {input_file} -> {output_file}")
return output_file
def convert_directory(self, input_dir, output_dir=None, css_path=None):
"""Konvertiert alle Markdown-Dateien in einem Verzeichnis"""
input_path = Path(input_dir)
if not input_path.exists():
raise FileNotFoundError(f"Verzeichnis nicht gefunden: {input_dir}")
if output_dir is None:
output_dir = input_path / "html_output"
else:
output_dir = Path(output_dir)
output_dir.mkdir(exist_ok=True)
# Alle .md Dateien finden
md_files = list(input_path.glob("**/*.md"))
if not md_files:
print(f"⚠️ Keine Markdown-Dateien gefunden in: {input_dir}")
return
print(f"📁 Konvertiere {len(md_files)} Markdown-Dateien...")
for md_file in md_files:
# Relativen Pfad beibehalten
relative_path = md_file.relative_to(input_path)
output_file = output_dir / relative_path.with_suffix('.html')
# Verzeichnis erstellen falls nötig
output_file.parent.mkdir(parents=True, exist_ok=True)
try:
self.convert_markdown_file(md_file, output_file, css_path)
except Exception as e:
print(f"❌ Fehler bei {md_file}: {e}")
def main():
parser = argparse.ArgumentParser(
description="PowerON Markdown zu HTML Konverter",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Beispiele:
python md_to_html_converter.py document.md
python md_to_html_converter.py document.md -o output.html
python md_to_html_converter.py -d ./docs -o ./html_output
python md_to_html_converter.py document.md -c ../styles/custom.css
"""
)
parser.add_argument('input', nargs='?', help='Markdown-Datei oder Verzeichnis')
parser.add_argument('-o', '--output', help='Output-Datei oder -verzeichnis')
parser.add_argument('-d', '--directory', help='Verzeichnis mit Markdown-Dateien konvertieren')
parser.add_argument('-c', '--css', default='poweron-styles.css', help='CSS-Datei (Standard: poweron-styles.css)')
parser.add_argument('--version', action='version', version='PowerON MD to HTML Converter 1.0')
args = parser.parse_args()
if not args.input and not args.directory:
parser.print_help()
return
try:
converter = PowerONHTMLConverter(args.css)
if args.directory:
converter.convert_directory(args.directory, args.output, args.css)
else:
converter.convert_markdown_file(args.input, args.output, args.css)
print("Konvertierung abgeschlossen!")
except Exception as e:
print(f"Fehler: {e}")
sys.exit(1)
if __name__ == "__main__":
main()

Binary file not shown.