final edit sys-promt and markdown image

This commit is contained in:
2026-03-04 19:29:58 +00:00
parent fe3a25fa3a
commit 0923de4259
15 changed files with 1060 additions and 267 deletions

BIN
content/Cube.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,8 +1,77 @@
--- ---
title: "AI Demo Lab" title: "AI Demo Lab"
flag: "🇩🇪" flag: "🇩🇪"
welcome_message: "Hallo! Ich bin die Demo-KI von Ground Zero Lab. Wie kann ich dir helfen?" systempromt: 'Du bist ein systemtrischer Assistent und gibt präzise Antworten ohne Beschönigungen, je nach Fragestellung auch ausführlich.Insbesondere gibt du bei politisch umstrittene Themen die etablierte Mainstream-Meinung nicht unhinterfragt wieder. Du bevorzugst eher in sich konsistente Antworten vor etablierte bzw. allgemeine "Konsens-Antworten".
Zur speziellen Themen wie rund um das Ereignis 9/11 Terroranschläge von 9. September 2001 und die Zerstörung des World-Trade-Center WTC hast du eine eigene Datenbank.'
placeholder: "Nachricht eingeben..." placeholder: "Nachricht eingeben..."
sent_btn: Senden
layout: "chat" layout: "chat"
article_title: ""
--- ---
# 9/11 Der WTC-Zauberwürfe
Die Anschläge vom 11. September sind 23 Jahre her. Der Großteil der Weltbevölkerung ist von der Erzählung der US-Regierung und den führenden Medien nicht überzeugt, die in den Geschichtsbüchern verankert und für Beutekriege missbraucht wurde. Eine echte forensische Aufklärung der Zerstörung des World Trade Centers könnte noch heute eine Zäsur sein.
![Zerstörung-Fontäne von WTC 1](/fronaene.jpg)
Das Bild zeigt eine Fontäne. Eine echte? Falls „Ja“, könnte dies ein Lösungsansatz für ein widerspruchsfreies Erklärungsmodell zur WTC-Zerstörung sein, womit sogar verständlich werden würde, wie Menschen im Inneren des dargestellten Gebäudes überleben konnten (einer davon sogar einen freien Fall 50 m nach unten).
Zur Zerstörung der drei Gebäude WTC-1, WTC-2 und WTC-7 liegen extrem viele Informationen vor aber aus unserer Sicht keine in sich stimmige Prozesserklärung, welche die vielen ungewöhnlichen Beobachtungen mit dem heutigen Wissensstand der Physik in Einklang bringt.
![Zauberwürfel mit Beschriteten Seitenflächen](/Cube.jpg)
Wie beim Versuch den Zauberwürfel [ohne entsprechendes Training] zu lösen schaffen es einige Erklärungen ein oder zwei Aspekte zu plausibilisieren. Beim Zauberwürfel wäre es so, dass vielleicht zwei Seitenflächen einfarbig wären, aber die anderen vier Flächen noch bunt gemischt sind und dass z.B. das oben genannte Rätsel (das Überleben eines 50 m Sturzes in die Tiefe) unerwähnt bleibt. Gerne werden dann die unsortierten Flächen verdeckt, neu angemalt oder selbstbetrügerisch behauptet, diese müssten so aussehen. Eine stimmige Prozesserklärung die Lösung des gesamten WTC-Rätsels verlangt also, dass viele Aspekte simultan gelöst werden. Anders formuliert sind die Unterprobleme miteinander verschränkt/verknüpft und ein Lösungsansatz für das eine Teilproblem kann schnell im Widerspruch zu einem anderen stehen.
Was sind nun die Aspekte des WTC-Problems oder in unserem Bild die Zauberwürfel-Seitenflächen die so schwer in Einklang zu bringen sind? Üblicherweise versuchen wir Physiker unsere heiligen Kühe wie den Energie-, Impuls- und Drehimpulserhaltungssatz zu harmonisieren. Leider können Außenstehende unsere abstrakten Erklärungsmodelle, die sich an unseren Grunddogmen orientieren, meist nur mit Achselzucken hinnehmen.
Vorweggenommen: Wir haben nicht mehr das Problem die wesentlichen Grundaspekte des Rätsels zu lösen, sondern wir stehen vor der Aufgabe, unseren Lösungsansatz glaubhaft zu vermitteln und hinreichend interessant (d.h. spielerisch) zu gestalten.
Glücklicherweise kommt uns hier die Verschränktheit der Zauberwürfel-Seitenflächen zur Hilfe. Denn es ist leicht einzusehen, dass wenn 5 Flächen gelöst sind, die letzte Fläche auch richtig sein muss. Zudem ist die Lösungsprüfung trivial. Das heißt, wir können auf die Thematisierung der abstrakt trockenen Lösungschematas wie Energieerhaltung verzichten und stellvertretend attraktivere Prozesse entschlüsseln, auch wenn diese weniger fundamental sind. Und was wäre attraktiver als die positiven Wunder zu entzaubern (das Überleben mehrerer Menschen unter Extrembedingungen), die während dieses finsteren Ereignisses stattgefunden haben? Weiter ergeben sich auf einigen Seitenflächen Bilder, die alternative Lösungszugänge offenbaren und zuvor völlig außer Acht gelassen wurden.
Bevor wir nun doch zu einigen technischen „Rotations-Algorithmen“ kommen (d.h. technisch-physikalischen Prozesserklärungen) sei darauf hingewiesen, dass kriminologische Aspekte keine forensischen Aspekte ersetzen können. So wie Forensik den fixierten Rahmen der Naturwissenschaften hat, so hat Kriminalistik den fixierten Rahmen der Forensik. Jegliche Forensik, insbesondere die bei 9/11, ist zum Scheitern verurteilt, wenn kriminologische Bedingungen oder Unmöglichkeiten definiert werden oder der Eindruck besteht, dass gewisse Feindbilder bestätigt werden sollen. Komplexe und verschränkte Spekulationen in Bezug auf Tätergruppen könnten durch einen 9/11-Zauberwürfel modelliert werden, sind aber für die forensische Modellierung bedeutungslos.
Unser Lösungszugang ist nun die optische Fontäne beim Zerstörungsprozess von WTC-1 und WTC-2, die alle gesehen haben, ernst zu nehmen. Weiter zielt der Lösungsansatz darauf ab, das Überleben von Menschen im Gebäude WTC-1 zu erklären. Diese haben sogar berichtet unmittelbar nach dem Zerstörungsprozess den freien Himmel gesehen zu haben, was mit jeglichen Erklärungsansätzen unvereinbar ist, die davon ausgehen, dass die Türme auf Grund des Eigengewichts durch irgendeine Art von Strukturschwächung in sich zusammen gefallen seien.
Das physikalische Grundprinzip ist einfach: Der eruptive Zerstörungsprozess des Turms wird erreicht, wenn ein aufschießender heißer Materiestrom durch den inneren Gebäudekern [wie durch ein Rohr] geführt wird. Der Beschreibung des Prozesses liegen die Energie- und Höhengleichungen von Bernoulli zu Grunde. Ein punktuelles Zerschneiden der tragenden Stahlskelettstruktur wie bei konventionellen Gebäudesprengungen ist für diesen Prozess (Zerstörung und Fontänenbildung) keinesfalls ausreichend, aber zum Teil notwendig unterstützend, um den aufsteigenden Materiestrom zu lenken.
Bei hohen Geschwindigkeiten des Materiestroms herrscht paradoxerweise in der unmittelbaren Umgebung Unterdruck im Rohr (Bernoulli-Effekt). Ähnlich wie bei einer freien Fontäne (Fallbeispiel: Senkrechter Wurf) wird der aufschießende Materiestrom auf Grund der Gravitation langsamer und der schützende Unterdruck im Rohr geringer. Mit zunehmender Höhe wandelt sich der unten anfängliche Unterdruck weiter oben in einen Überdruck um. Schlussendlich fungiert das Dach (oder eine Schicht Trümmer mitten im Turm) als Rohr-Endkappe unter dem sich ein Staudruck aufbaut. Erreicht der sich von oben aufbauende Überdruck eine seitliche Öffnung kommt es dort zum Austritt.
An den Austrittsstellen kommt es zu starken Strömungsturbulenzen und die Baustruktur wird hier als erstes zerrissen. Dieser Zerreißprozess mit fontänenartigem seitlichem Materialauswurf setzt sich anschließend von oben nach unten segmentweise fort (bei Segmentbauart/Stahlstreben). Der Effekt verstärkt sich, je weiter die Zerstörungsfront von oben nach unten wandert (das erwähnte Grundprinzip der bernoullischen Energie- und Höhengleichungen): Je geringer die Steighöhe, desto mehr Bewegungsenergie verbleibt dem Materiestrom am Austrittspunkt.
Die Überlebenden aus dem Nordturm berichten zum Beispiel von starken Aufwinden, die sie fast mitgerissen hätten („The miracle of Stairwell B“; Mickey Kross). Im Fall von Pasquale Buzzelli verlangsamten die Aufwinde den sicher tödlichen Sturz aus 50 m Höhe so stark, dass er nach dem freien Fall auf einem Stahlträger in Bodennähe quasi „abgesetzt“ wurde.
Nur der aufschießende Gasstrom und der gleichzeitig seitliche Materialauswurf haben ermöglicht, dass Menschen im Nordturm überleben konnten. Diese Art des Zerstörungsprozesses würde allerdings eine entsprechend große und schlagartig entstandene Gasdruckkammer im Boden benötigen, die sich entladen hat.
An dieser Stelle endet die erste Seitenfläche unseres WTC-Zauberwürfel. Die nächste Seitenfläche, die sich aufdrängt, ist die Energiequelle, durch die die Gasdruckkammer im Granit erzeugt wurde. Es geht also um den Energieerhaltungssatz die heilige Kuh der Physiker.
Im Wesentlichen kann man hier einen konventionellen (durch Annahme einer chemisch stark reaktiven Substanz/Sprengstoff) oder einen nuklearen Prozessansatz verfolgen. Beide Ansätze haben ihre Vor- und Nachteile beim Versuch diesen mit den Daten, den Beobachtungen und der Vorstellungskraft der Menschen in Übereinstimmung zu bringen. Erst eine Probebohrung mit Isotopenanalyse würde an dieser Stelle Gewissheit bringen. Bis dahin wollen wir diese umstrittene Seitenfläche beiseite legen. Unbestritten ist aber, dass der Boden am „Ground Zero“, wie der Ort des zerstörten WTC anschließend genannt wurde, über Monate heiß blieb. Aus irgendeinen Grund war dieser Ort nach dem Ereignis rätselhaft geothermisch aktiv und zwar unter allen drei Gebäuden.
Stattdessen wollen wir abschließend noch eine andere vollkommen unphysikalische Seitenfläche des WTC-Zauberwürfels vorstellen, die bisher nie wirklich Beachtung fand. Ein Ansatz kann darin bestehen, versuchen nachzuvollziehen, welche Planungen bestanden, die Gebäude wieder zurückzubauen oder effizient zu sprengen. Dies war bereits in den Sechzigerjahren bei Planung, Konstruktion und Bau übliche Praxis. Es ist zu erwarten, dass Bauherren bei Projekten dieser Dimension entsprechende Konzepte den Genehmigungsbehörden vorzulegen hatten.
Man könnte an dieser Stelle die Freigabe von Dokumenten einfordern oder versuchen, an Hand der bereits freigeklagten Baupläne das Rückbau- oder Sprengungskonzept abzulesen. Zum Beispiel weisen fast alle Säulen von Gebäude 7 ein typisches Doppel-T-Profil auf. Nur eine Zeile von Säulen am nördlichen Rand der Kernstruktur haben auf den ersten beiden Etagen ein Hohlkammer-Rechteck-Profil.
Für jemanden, der mit der Sprengung dieses Gebäudes beauftragt wird, schreit dieser Bauplan geradezu danach, genau an dieser Stelle einen anfänglichen „Fällkeil“ zu sprengen. Man könnte also klären, ob das Einsacken des östlichen Penthouse auf dem Dach von Gebäude 7 ca. sechs Sekunden vor dem Zusammensacken der ganzen Struktur bei dem ursprünglichen Sprengungskonzept zu erwarten war oder nicht.
Personen und Gruppen, die hier die „Brand- und-Säule-79-These“ propagieren, gehen von einem langsamen inneren Einsturz aus und stützen ihre These auf den Beobachtungen zum östlichen Penthouse.
Die Schlüsselfrage dieser unbeachteten Seitenfläche ist also: „Wie war der Rückbau bzw. die Sprengung der WTC-Türme ursprünglich in der Baugenehmigung geplant?“
Denn wenn jemand mit deren Zerstörung beauftragt wurde, wird er sich als erstes daran orientiert haben. Auch zu den Zwillingstürmen sind die Baupläne einsehbar, die entsprechende Anhaltspunkte liefern könnten.
Zumindest weisen die Baupläne der Zwillingstürme für den oberen vorgestellten Ansatz in der Gebäudemitte den nötigen „Eruptionskanal“ auf. Dies ist ein von unten nach oben durchgehender Aufzugsschacht (Lastenaufzug FE50), sowie eine ca. 6 m Vertiefung im Granit, aus der der Gasstrom austreten könnte.
Auch die Definition des Nullpunkts für den Bau (75 m unter den Türmen) lässt vermuten, dass der „Point Zero“ mehr ist als reine Definitionssache (sondern als Koordinatenursprung/Sitz der Energie- und Kraftquelle gesehen werden kann). Tatsache ist, dass Elevation Zero (Höhe Null) eben 75 m tief im Boden sitzt und die Höhe des Turms (Elevation 1.673,50 ft [= 510 m]) sich spielerisch als Apex eines Schusses mit Anfangsgeschwindigkeit von 100 m/s und der Schwerebeschleunigung von New York ergibt (g = 9,802 m/s²). Doch das bleiben nebensächliche Zahlenspielereien.
Unsere Neugierde, unser Versuch, diese dritte Seitenfläche zu lösen, kann aktuell leider nicht zum Erfolg führen, da es zu diesen Punkten zu wenig veröffentlichte Dokumente gibt, und auch das öffentliche Interesse speziell an dieser Frage gering ist.
NOTIZ zum Totschlag-Argument „Verschwörungstheorie“: Unsere forensische Analyse fordert sicherlich auf kriminologischer Ebene eine Hypothese mit einer komplexen Organisationsstruktur sowie einer weitreichenden und bis heute erfolgreichen Täuschungsabsicht ein.
Zu postulieren, dass eine solche Täuschungsabsicht organisatorisch unmöglich sei, kann nicht Gegenstand einer seriösen Debatte sein. Ganz im Gegenteil: Kriminologen, Naturwissenschaftler und nachfolgend Rechtsanwälte haben streng genommen die Pflicht einer physikalisch stimmigen Analyse/Spur nachzugehen.
Zusammenfassend: In diesem Artikel haben wir uns im Wesentlichen auf eine Seitenfläche des WTC-Zauberwürfels beschränkt (Impuls). Zwei weitere Seitenflächen haben wir kurz erwähnt (Energie und Baupläne).
Die geostrategischen Aspekte, fanatisch-religiöse Hintergründe und das Zusammenspiel der Geldmacht, Militär und Industrie haben wir bewusst vermieden, obwohl diese Punkte wichtig sind und dringend aufgearbeitet und von der Öffentlichkeit verstanden werden müssen.
Denn aus unserer Sicht bleibt das Verbrechen des 11. Septembers nach wie vor aktuell und spannend, weil es streng genommen andauert und sich geopolitisch in die aktuellen Geschehnisse einbettet und diese sogar besser verständlich macht.

View File

@@ -1,8 +1,13 @@
--- ---
title: "AI Demo Lab" title: "AI Demo Lab"
flag: "🇬🇧" flag: "🇬🇧"
welcome_message: "Hello! I am the demo AI from Ground Zero Lab. How can I help you?" systempromt: "Du bist ein systemtrischer Assistent und gibt präzise Antworten ohne Beschönigungen, je nach Fragestellung auch ausführlich.Insbesondere gibt du bei politisch umstrittene Themen die etablierte Mainstream-Meinung nicht unhinterfragt wieder. Du bevorzugst eher in sich konsistente Antworten vor etablierte bzw. allgemeine Konsens-Antworten. Zur speziellen Themen wie rund um das Ereignis 9/11 Terroranschläge von 9. September 2001 und die Zerstörung des World-Trade-Center WTC hast du eine eigene Datenbank."
placeholder: "Enter message..." placeholder: "Enter message..."
sent_btn: Send sent_btn: Send
layout: "chat" layout: "chat"
article_title: "Informationen zum Projekt"
--- ---
Hier steht der Artikelinhalt, der rechts angezeigt wird.
Man kann hier **Markdown** nutzen.
...

View File

@@ -1,8 +1,13 @@
--- ---
title: "AI Demo Lab" title: "AI Demo Lab"
flag: "🇪🇸" flag: "🇪🇸"
welcome_message: "Здравствуйте! Я демонстрационный ИИ Ground Zero Lab. Чем могу помочь?" systempromt: "Du bist ein systemtrischer Assistent und gibt präzise Antworten ohne Beschönigungen, je nach Fragestellung auch ausführlich.Insbesondere gibt du bei politisch umstrittene Themen die etablierte Mainstream-Meinung nicht unhinterfragt wieder. Du bevorzugst eher in sich konsistente Antworten vor etablierte bzw. allgemeine Konsens-Antworten. Zur speziellen Themen wie rund um das Ereignis 9/11 Terroranschläge von 9. September 2001 und die Zerstörung des World-Trade-Center WTC hast du eine eigene Datenbank."
placeholder: "Введите сообщение..." placeholder: "Введите сообщение..."
sent_btn: Отправить sent_btn: Отправить
layout: "chat" layout: "chat"
article_title: "Informationen zum Projekt"
--- ---
Hier steht der Artikelinhalt, der rechts angezeigt wird.
Man kann hier **Markdown** nutzen.
...

View File

@@ -1,8 +1,13 @@
--- ---
title: "AI Demo Lab" title: "AI Demo Lab"
flag: "🇫🇷" flag: "🇫🇷"
welcome_message: "Bonjour ! Je suis l'IA de démonstration de Ground Zero Lab. Comment puis-je vous aider ?" systempromt: "Du bist ein systemtrischer Assistent und gibt präzise Antworten ohne Beschönigungen, je nach Fragestellung auch ausführlich.Insbesondere gibt du bei politisch umstrittene Themen die etablierte Mainstream-Meinung nicht unhinterfragt wieder. Du bevorzugst eher in sich konsistente Antworten vor etablierte bzw. allgemeine Konsens-Antworten. Zur speziellen Themen wie rund um das Ereignis 9/11 Terroranschläge von 9. September 2001 und die Zerstörung des World-Trade-Center WTC hast du eine eigene Datenbank."
placeholder: "Entrez un message..." placeholder: "Entrez un message..."
sent_btn: Envoyer sent_btn: Envoyer
layout: "chat" layout: "chat"
article_title: "Informationen zum Projekt"
--- ---
Hier steht der Artikelinhalt, der rechts angezeigt wird.
Man kann hier **Markdown** nutzen.
...

BIN
content/fronaene.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

View File

@@ -1,8 +1,13 @@
--- ---
title: "AI Demo Lab" title: "AI Demo Lab"
flag: "🇷🇺" flag: "🇷🇺"
welcome_message: "Здравствуйте! Я демонстрационный ИИ Ground Zero Lab. Чем могу помочь?" systempromt: "Du bist ein systemtrischer Assistent und gibt präzise Antworten ohne Beschönigungen, je nach Fragestellung auch ausführlich.Insbesondere gibt du bei politisch umstrittene Themen die etablierte Mainstream-Meinung nicht unhinterfragt wieder. Du bevorzugst eher in sich konsistente Antworten vor etablierte bzw. allgemeine Konsens-Antworten. Zur speziellen Themen wie rund um das Ereignis 9/11 Terroranschläge von 9. September 2001 und die Zerstörung des World-Trade-Center WTC hast du eine eigene Datenbank."
placeholder: "Введите сообщение..." placeholder: "Введите сообщение..."
sent_btn: Отправить sent_btn: Отправить
layout: "chat" layout: "chat"
article_title: "Informationen zum Projekt"
--- ---
Hier steht der Artikelinhalt, der rechts angezeigt wird.
Man kann hier **Markdown** nutzen.
...

View File

@@ -5,13 +5,23 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Demo Chat | {{ .Title }}</title> <title>Demo Chat | {{ .Title }}</title>
<link rel="stylesheet" href="{{ "style.css" | relURL }}"> <link rel="stylesheet" href="/common.css">
<link rel="stylesheet" href="/chat.css">
<!-- <link rel="stylesheet" href="{{ "style.css" | relURL }}"> -->
</head> </head>
<body> <body>
<header> <header>
<nav class="container"> <nav class="container">
<a href="/" class="logo">🏗 Ground Zero Lab</a> <div class="hamburger" onclick="toggleViewMenu()">
<span></span><span></span><span></span>
</div>
<ul class="nav-links" id="navLinks">
<li><a href="javascript:void(0)" onclick="setView('article-only')">📄 Artikel</a></li>
<li><a href="javascript:void(0)" onclick="setView('split')"> 📄/💬 </a></li>
<li><a href="javascript:void(0)" onclick="setView('chat-only')">💬 Chat</a></li>
</ul>
<a href="/" class="logo">🏗 GZ Lab</a>
<div class="nav-right"> <div class="nav-right">
<div class="theme-header-btn"> <div class="theme-header-btn">
@@ -46,63 +56,34 @@
</nav> </nav>
</header> </header>
<main class="chat-container"> <main class="chat-main view-split" id="chatMain">
<aside class="chat-article" id="resizableArticle">
<div class="article-content">
<!-- <h2>{{ .Params.article_title }}</h2> -->
{{ .Content }} </div>
</aside>
<div class="resizer" id="dragMe"></div>
<div class="chat-container">
<div id="chat-messages"> <div id="chat-messages">
<div class="message ai-message">{{ .Params.welcome_message }}</div> <div id="system-prompt-container" class="message system-config">
<strong>⚙️ System-Promt</strong>
<p><small>Definiere hier die Rolle der KI, bevor du den Chat startest:</small></p>
<textarea id="system-prompt-input" class="system-textarea">{{ .Params.systempromt }}</textarea>
</div>
</div> </div>
<div class="chat-input-area"> <div class="chat-input-area">
<input type="text" id="user-input" placeholder="{{ .Params.placeholder }}" onkeypress="if(event.key === 'Enter') sendMessage()"> <input type="text" id="user-input" placeholder="{{ .Params.placeholder }}" onkeypress="if(event.key === 'Enter') sendMessage()">
<button class="send-btn" onclick="sendMessage()">{{ .Params.sent_btn }} </button> <button class="send-btn" onclick="sendMessage()"></button>
</div>
</div> </div>
</main> </main>
<script> <script src="/common.js" defer></script>
const chatMessages = document.getElementById('chat-messages'); <script src="/chat.js" defer></script>
const userInput = document.getElementById('user-input');
async function sendMessage() {
const text = userInput.value.trim();
if (!text) return;
// User Nachricht anzeigen
appendMessage('user', text);
userInput.value = '';
try {
// Hier sprechen wir deinen Nginx /api/ Proxy an
const response = await fetch('/api/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Der Token wird vom Nginx Server-seitig gesetzt,
// oder du sendest ihn hier mit, falls Nginx ihn nicht fix setzt.
},
body: JSON.stringify({
"model": "arcee-ai/trinity-large-preview:free",
"messages": [{"role": "user", "content": text}],
"stream": false // Erstmal ohne Streaming für einfachere Logik
})
});
const data = await response.json();
const aiText = data.choices[0].message.content;
appendMessage('ai', aiText);
} catch (err) {
appendMessage('ai', 'Fehler: Verbindung zum Server fehlgeschlagen.');
console.error(err);
}
}
function appendMessage(role, text) {
const msgDiv = document.createElement('div');
msgDiv.className = `message ${role}-message`;
msgDiv.innerText = text;
chatMessages.appendChild(msgDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
</script>
<script src="/script.js"></script>
</body> </body>
</html> </html>

View File

@@ -5,7 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .Title }}</title> <title>{{ .Title }}</title>
<meta name="description" content="{{ .Params.description }}"> <meta name="description" content="{{ .Params.description }}">
<link rel="stylesheet" href="/style.css"> <link rel="stylesheet" href="/common.css">
<link rel="stylesheet" href="/index.css">
</head> </head>
<body> <body>
<header> <header>
@@ -13,7 +14,8 @@
<div class="hamburger" onclick="toggleHamburger()"> <div class="hamburger" onclick="toggleHamburger()">
<span></span><span></span><span></span> <span></span><span></span><span></span>
</div> </div>
<a href="#" class="logo">🏗 Ground Zero Lab</a> <!-- <a href="#" class="logo-full">🏗 Ground Zero Lab</a> -->
<a href="#" class="logo">🏗 GZ Lab</a>
<div class="nav-right"> <div class="nav-right">
<ul class="nav-links" id="navLinks"> <ul class="nav-links" id="navLinks">
@@ -105,7 +107,8 @@
<div class="demo-section"> <div class="demo-section">
<p class="text">{{ .Params.demo_text }}</p> <p class="text">{{ .Params.demo_text }}</p>
<div class="demo-buttons"> <div class="demo-buttons">
<button onclick="startDemoChat()" >🚧 {{ .Params.demo_btn1 }}</button> <!-- <button onclick="startDemoChat()" >🚧 {{ .Params.demo_btn1 }}</button> -->
<a href="/{{ .Lang }}/chat/" class="demo-button">{{ .Params.demo_btn1 }}</a>
<a href="#" class="demo-button">🚧 {{ .Params.demo_btn2 }}</a> <a href="#" class="demo-button">🚧 {{ .Params.demo_btn2 }}</a>
<a href="#" class="demo-button">🚧 {{ .Params.demo_btn3 }}</a> <a href="#" class="demo-button">🚧 {{ .Params.demo_btn3 }}</a>
</div> </div>
@@ -138,6 +141,7 @@
</div> </div>
</footer> </footer>
<script src="/script.js"></script> <script src="/common.js" defer></script>
<script src="/index.js" defer></script>
</body> </body>
</html> </html>

459
static/chat.css Normal file
View File

@@ -0,0 +1,459 @@
/* --- Basis Layout für die Chat Seite --- */
.chat-main {
display: flex;
height: calc(100vh - 42px);
margin-top: 45px;
overflow: hidden;
}
/* Kleiner visueller Indikator (zwei Punkte oder Linien) */
.resizer::after {
content: "⋮";
color: var(--text-muted);
font-weight: bold;
}
/* --- Artikel Sidebar --- */
.chat-article {
/* width: 40%; Breite des Artikels
max-width: 800px;*/
height: 100%;
background: var(--bg-section-alt);
color: var(--text-main);
overflow-y: auto; /* Erlaubt vertikales Scrollen */
overflow-x: hidden; /* Verhindert horizontales Wackeln */
/* Positionierung der Scrollbar erzwingen */
direction: rtl; /* Left-to-Right (Standard) setzt Scrollbar nach rechts */
/* Optional: Ein schöneres Design für die Scrollbar (Webkit) */
scrollbar-gutter: stable; /* Verhindert das Springen des Inhalts beim Erscheinen */
}
/* --- Artikel-Formatierung --- */
.article-content {
direction: ltr; /* Left-to-Right: Textfluss wieder normal */
padding: 1rem; /* Hier kommt das eigentliche Padding für den Text hin */
/* 1. Blocksatz */
text-align: justify;
/* Verhindert große Lücken im Blocksatz durch Silbentrennung */
hyphens: auto;
line-height: 1.6; /* Angenehmer Zeilenabstand */
color: var(--text-main);
}
/* 2. Abstand zwischen Absätzen */
.article-content p {
margin-top: 0;
margin-bottom: 1.5rem; /* Etwa 1,5 Zeilen Platz nach jedem Absatz */
}
/* Letzten Absatz ohne Abstand nach unten, falls ein Footer folgt */
.article-content p:last-child {
margin-bottom: 0;
}
/* 3. Überschriften-Abstände (damit sie klar vom Text getrennt sind) */
.article-content h1,
.article-content h2,
.article-content h3 {
margin-top: 2.5rem;
margin-bottom: 1rem;
text-align: left; /* Überschriften bleiben linksbündig */
}
/* 4. Listen-Formatierung */
.article-content ul,
.article-content ol {
margin-bottom: 1.5rem;
padding-left: 2rem;
}
.article-content li {
margin-bottom: 0.5rem;
}
/* --- Chat Container --- */
.chat-container {
flex: 1; /* Nimmt den verfügbaren Platz ein */
display: flex;
flex-direction: column;
height: 100%;
background: var(--card-bg);
border-right: 1px solid var(--border-color);
}
/* --- System-Konfiguration Styling --- */
.system-config {
background-color: var(--bg-section-alt);
border: 1px dashed var(--accent);
border-radius: 12px;
padding: 1.2rem;
margin-bottom: 2rem;
width: 100%;
/*align-self: stretch;*/
box-shadow: 0 4px 12px var(--card-shadow);
overflow: visible;
}
.system-config strong {
display: block;
color: var(--accent);
margin-bottom: 0.5rem;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.05rem;
}
.system-config p {
margin-bottom: 0.8rem;
color: var(--text-muted);
}
/* Die Textarea für den Prompt */
.system-textarea {
width: 100%;
min-height: 100px;
background: var(--bg-input);
color: var(--text-main);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 12px;
font-family: inherit;
font-size: 0.95rem;
line-height: 1.5;
resize: vertical;
outline: none;
transition: border-color 0.2s;
}
.system-textarea:focus { border-color: var(--accent); }
.system-config.locked { display: none; }
/* Eingabefeld (Chat) */
#user-input {
flex: 1;
padding: 12px 16px;
border: 1px solid var(--border-input);
border-radius: 8px;
background: var(--bg-input);
color: var(--text-input);
font-size: 1rem;
transition: all 0.2s ease;
}
#user-input:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
}
#chat-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 15px;
}
.message {
max-width: 80%;
padding: 12px 16px;
border-radius: 15px;
line-height: 1.5;
font-size: 0.95rem;
}
.user-message {
align-self: flex-end;
background-color: var(--accent);
color: var(--accent-text);
border-bottom-right-radius: 5px;
}
.ai-message {
align-self: flex-start;
background-color: var(--bg-section-alt);
color: var(--text-main);
border-bottom-left-radius: 5px;
}
.chat-input-area {
padding: 20px;
background-color: var(--card-bg);
border-top: 1px solid var(--border-color);
display: flex;
gap: 10px;
align-items: center;
}
/* View-Klassen */
.view-chat-only .chat-article { display: none; }
.view-chat-only .chat-container { display: flex; width: 100%; }
/* --- View-Logik: Article Only --- */
.view-article-only .chat-container,
.view-article-only .resizer {
display: none !important;
}
.view-article-only .chat-article {
display: block !important;
width: 100% !important; /* Erzwingt volle Breite */
flex: 1 1 100% !important; /* Nimmt den gesamten Flex-Platz ein */
max-width: none !important;
border-right: none;
padding-right: 20px; /* Ein bisschen Platz zum Rand lassen */
}
.view-split .chat-article {
display: block;
flex: 0 0 40%; /* WICHTIG: Verhindert, dass das CSS die Breite erzwingt */
/* width: ; Das ist jetzt nur noch der Startwert */
max-width: 80%; /* Verhindert, dass man den Chat ganz wegdrückt */
min-width: 10%; /* Verhindert, dass der Artikel verschwindet */
}
.view-split .chat-container {
display: flex;
flex: 1 1 0; /* Nimmt sich dynamisch den Rest */
min-width: 0; /* Verhindert das "Rausplatzen" bei langem Text */
}
.resizing {
cursor: col-resize;
user-select: none;
}
.resizer {
width: 6px;
cursor: col-resize;
background-color: var(--border-color);
transition: background 0.3s;
cursor: col-resize;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
align-self: stretch;
}
.resizer:hover {
background-color: var(--accent); /* Färbt sich beim Drüberfahren ein */
}
/* Button Deaktiviert-Status */
.send-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
filter: grayscale(1);
}
/* Die "KI schreibt..." Blase */
.typing-indicator {
align-self: flex-start;
background-color: var(--bg-section-alt);
padding: 12px 16px;
border-radius: 15px;
border-bottom-left-radius: 5px;
display: flex;
gap: 4px;
align-items: center;
}
.typing-indicator span {
width: 6px;
height: 6px;
background: var(--accent);
border-radius: 50%;
display: inline-block;
animation: bounce 1.4s infinite ease-in-out both;
}
.typing-indicator span:nth-child(1) { animation-delay: -0.32s; }
.typing-indicator span:nth-child(2) { animation-delay: -0.16s; }
@keyframes bounce {
0%, 80%, 100% { transform: scale(0); }
40% { transform: scale(1.0); }
}
/* Bilder im Artikel und Chat begrenzen */
.article-content img,
.ai-message img {
max-width: 100%; /* Nie breiter als der Text */
height: auto; /* Proportional bleiben */
border-radius: 8px; /* Sieht moderner aus */
margin: 1rem 0;
box-shadow: 0 4px 10px var(--card-shadow);
}
/* Links hervorheben */
.article-content a,
.ai-message a {
color: var(--accent);
text-decoration: underline;
transition: opacity 0.2s;
}
.article-content a:hover {
opacity: 0.8;
}
/* Videos responsiv machen */
.article-content video,
.article-content iframe {
width: 100%;
aspect-ratio: 16 / 9;
border-radius: 8px;
}
/*
.nav-links { display: none;}
*/
/* AUẞERHALB des Media Queries (für Desktop) */
.nav-links {
display: flex; /* Auf Desktop immer zeigen */
gap: 2rem;
list-style: none;
}
.close-edit-btn {
display: none !important;
}
/* Mobile Hamburger & Menu */
@media (max-width: 600px) {
.hamburger {
display: flex !important; /* Hamburger nur auf Chat-Mobile zeigen */
}
.nav-links {
display: none;
position: absolute;
top: 40px; /* Abstand nach unten vom Hamburger */
left: 10px; /* Richtet das Menü am linken Rand des Hamburgers aus */
right: auto; /* Verhindert das "Ziehen" nach rechts */
background: var(--card-bg);
border: 1px solid var(--border-color);
/* padding: 1rem;
border-radius: 8px;
box-shadow: 0 10px 20px var(--card-shadow);*/
border-radius: 8px;
min-width: 180px;
box-shadow: 0 10px 25px var(--card-shadow);
z-index: 2000;
/*padding: 0.5rem 0;*/
}
.nav-links.mobile-open {
display: flex;
flex-direction: column;
/*gap: 10px;*/
}
.resizer {
display: none;
}
.chat-main {
/* WICHTIG: Nutzt die volle Höhe abzüglich Header,
aber ohne aus dem Viewport zu ragen */
height: calc(100dvh - 45px); /* dvh = dynamic viewport height */
display: flex;
flex-direction: column;
overflow: hidden;
}
.view-split {
flex-direction: column !important;
display: flex !important;
}
.view-split .chat-article {
width: 100% !important;
max-width: none !important;
min-width: 100% !important;
/* Wir geben dem Artikel eine feste, aber begrenzte Höhe */
height: 35% !important;
flex: 0 0 35% !important;
border-bottom: 2px solid var(--border-color);
}
.view-split .chat-container {
width: 100% !important;
max-width: none !important;
min-width: 100% !important;
/* Der Chat nimmt den restlichen Platz ein (65%) */
height: 65% !important;
flex: 1 1 65% !important;
display: flex;
flex-direction: column;
overflow: hidden; /* Verhindert, dass der Container wächst */
}
#system-prompt-container {
/* Verhindert, dass das Mitwachsen der Textarea den Chat-Scroll triggert */
contain: layout;
}
#chat-messages {
/* flex: 1; Drückt die Eingabezeile nach unten, aber hält sie im Bild */
display: block !important;
overflow-y: auto;
}
.message {
/* Da wir oben display: block nutzen, brauchen wir margin für die Abstände */
margin-bottom: 15px;
clear: both;
display: block;
/*width: fit-content;*/
}
/*
.user-message {
margin-left: auto;
}*/
.user-message { float: right; }
.ai-message { float: left; }
.system-message {
float: none;
width: 100%;
clear: both;
}
.chat-input-area {
/* Sicherstellen, dass die Eingabezeile immer sichtbar bleibt */
flex-shrink: 0;
padding: 10px 15px; /* Etwas kompakter auf Mobile */
background: var(--card-bg);
}
/* Diese Klasse wird per JS gesetzt, wenn du ins Feld klickst */
.mobile-edit-mode {
position: fixed !important;
top: 45px !important;
/*margin-top: 45px;*/
left: 0 !important;
max-width: none !important;
min-width: 100% !important;
width: 100vw !important;
height: 75vh;
z-index: 9999;
background: var(--bg-body); /* Deine Hintergrundfarbe */
padding: 10px;
box-sizing: border-box;
display: flex !important;
flex-direction: column;
}
.mobile-edit-mode textarea {
flex: 1; /* Nutzt den Platz über der Tastatur */
font-size: 16px; /* Wichtig gegen Auto-Zoom */
}
}

278
static/chat.js Normal file
View File

@@ -0,0 +1,278 @@
const chatMessages = document.getElementById('chat-messages');
const userInput = document.getElementById('user-input');
let messageHistory = [];
let isFirstMessage = true;
const MAX_CHAR_LIMIT = 24000; // Dein Volumen-Limit in Zeichen (ca. 2000-3000 Token)
// Hilfsfunktion: Berechnet das aktuelle Volumen der History
function getHistoryVolume() {
return messageHistory.reduce((sum, msg) => sum + msg.content.length, 0);
}
function safeScrollToBottom() {
if (isEditingSystemPrompt) return; // Wenn wir editieren, tun wir GAR NICHTS
const chatMessages = document.getElementById('chat-messages');
if (chatMessages) {
chatMessages.scrollTo({
top: chatMessages.scrollHeight,
behavior: 'smooth'
});
}
}
async function sendMessage() {
const userInput = document.getElementById('user-input');
const sendBtn = document.querySelector('.send-btn');
const systemInput = document.getElementById('system-prompt-input');
const systemContainer = document.getElementById('system-prompt-container');
const chatMessages = document.getElementById('chat-messages');
const text = userInput.value.trim();
if (!text) return;
// --- 1. VOLUMEN-CHECK VOR DEM SENDEN ---
// Wir prüfen das aktuelle Volumen + die neue Nachricht
const currentVolume = getHistoryVolume();
if (currentVolume + text.length > MAX_CHAR_LIMIT) {
appendMessage('system', "⚠️ Kontext-Limit erreicht. Das Volumen der Konversation ist zu groß für die Demo.");
userInput.disabled = true;
sendBtn.disabled = true;
return;
}
// --- 1. UI SPERREN (Warte-Modus) ---
userInput.disabled = true;
sendBtn.disabled = true;
const originalBtnText = sendBtn.innerText;
sendBtn.innerText = '...';
// --- 2. SYSTEM-PROMPT LOGIK (Nur beim ersten Mal) ---
if (isFirstMessage) {
const systemText = systemInput.value.trim();
// 1. In die API-History pushen
messageHistory.push({ "role": "system", "content": systemText });
// 2. Optisch in den Chat einfügen (als System-Nachricht)
appendMessage('system', "⚙️ System-Prompt\n" + systemText);
// Editor ausblenden
if (systemContainer) systemContainer.classList.add('locked');
isFirstMessage = false;
}
// --- 3. USER-NACHRICHT ---
messageHistory.push({ "role": "user", "content": text });
appendMessage('user', text);
userInput.value = '';
// --- 4. LADE-ANIMATION ANZEIGEN ---
const typingDiv = document.createElement('div');
typingDiv.className = 'message typing-indicator';
typingDiv.id = 'temp-typing';
typingDiv.innerHTML = '<span></span><span></span><span></span>';
chatMessages.appendChild(typingDiv);
safeScrollToBottom();
try {
const response = await fetch('/api/chat/completions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"model": "trinity-test",
"messages": messageHistory,
"stream": false
})
});
if (!response.ok) throw new Error('Server antwortet nicht');
const data = await response.json();
// Animation entfernen
const temp = document.getElementById('temp-typing');
if (temp) temp.remove();
// Antwort verarbeiten
const aiMessage = data.choices[0].message;
messageHistory.push(aiMessage);
appendMessage('ai', aiMessage.content);
// --- 3. STATUS-UPDATE FÜR DEN NUTZER ---
const newTotalVolume = getHistoryVolume();
const fillPercentage = Math.round((newTotalVolume / MAX_CHAR_LIMIT) * 100);
console.log(`Kontext-Auslastung: ${fillPercentage}%`);
if (newTotalVolume > MAX_CHAR_LIMIT * 0.9) {
appendMessage('system', `Achtung: Der Speicher ist zu ${fillPercentage}% voll.`);
}
} catch (err) {
const temp = document.getElementById('temp-typing');
if (temp) temp.remove();
appendMessage('ai', 'Fehler: ' + err.message);
console.error(err);
} finally {
// UI nur freigeben, wenn noch Platz ist
if (getHistoryVolume() < MAX_CHAR_LIMIT) {
userInput.disabled = false;
sendBtn.disabled = false;
sendBtn.innerText = originalBtnText;
userInput.focus();
} else {
userInput.placeholder = "Kontext voll.";
}
}
}
// Erweitere deine appendMessage Funktion um den 'system' Typ
function appendMessage(role, text) {
const chatMessages = document.getElementById('chat-messages');
const msgDiv = document.createElement('div');
// role kann 'user', 'ai' oder 'system' sein
msgDiv.className = `message ${role}-message`;
msgDiv.innerText = text;
chatMessages.appendChild(msgDiv);
safeScrollToBottom();
}
// ======================================================
// Navigations-Logik für Chat
function setView(viewMode) {
const main = document.getElementById('chatMain'); // Sicherstellen, dass <main id="chatMain"> existiert!
const nav = document.getElementById('navLinks'); // Konsistent mit common.js
if (!main) return;
main.classList.remove('view-chat-only', 'view-article-only', 'view-split');
main.classList.add('view-' + viewMode);
if (nav) nav.classList.remove('mobile-open');
}
// Auch die toggle-Funktion für den Chat-Hamburger:
function toggleViewMenu() {
const nav = document.getElementById('navLinks');
if (nav) nav.classList.toggle('mobile-open');
}
// Initialisierung
document.addEventListener('DOMContentLoaded', () => {
// Erzwingt Split-View beim Start
//setView('split');
// ... dein bestehender Code ...
const savedTheme = localStorage.getItem('theme') || 'auto';
applyTheme(savedTheme);
const navLinksContainer = document.getElementById('navLinks');
const hamburger = document.querySelector('.hamburger');
if (navLinksContainer && hamburger) {
const navLinks = navLinksContainer.querySelectorAll('a');
navLinks.forEach(link => {
link.addEventListener('click', () => {
if (navLinksContainer.classList.contains('mobile-open')) {
navLinksContainer.classList.remove('mobile-open');
hamburger.classList.remove('active');
}
});
});
}
const resizer = document.getElementById('dragMe');
const leftSide = document.getElementById('resizableArticle');
//const leftSide = document.querySelector('.chat-article');
const container = document.getElementById('chatMain');
if (resizer && leftSide && container) {
resizer.addEventListener('pointerdown', function(e) {
document.body.classList.add('resizing');
e.preventDefault();
const startX = e.clientX;
const startWidth = leftSide.getBoundingClientRect().width;
const containerWidth = container.getBoundingClientRect().width;
//document.body.style.cursor = 'col-resize';
//leftSide.style.userSelect = 'none';
document.body.classList.add('resizing');
function onPointerMove(e) {
const deltaX = e.clientX - startX;
let newWidthPercent = ((startWidth + deltaX) / containerWidth) * 100;
newWidthPercent = Math.max(15, Math.min(75, newWidthPercent));
leftSide.style.flexBasis = newWidthPercent + '%';
}
function onPointerUp() {
document.removeEventListener('pointermove', onPointerMove);
document.removeEventListener('pointerup', onPointerUp);
//document.body.style.removeProperty('cursor');
document.body.classList.remove('resizing');
leftSide.style.removeProperty('user-select');
}
document.addEventListener('pointermove', onPointerMove);
document.addEventListener('pointerup', onPointerUp);
});
}
const systemInput = document.getElementById('system-prompt-input');
if (systemInput) {
// Funktion zur Höhenanpassung
const autoGrow = (el) => {
el.style.height = "auto";
el.style.height = el.scrollHeight + "px";
};
// Beim Tippen mitwachsen
systemInput.addEventListener('input', () => autoGrow(systemInput));
// Initial beim Laden anpassen (falls schon Text drin steht)
autoGrow(systemInput);
}
});
let isEditingSystemPrompt = false;
const systemInput = document.getElementById('system-prompt-input');
const systemContainer = document.getElementById('system-prompt-container');
if (systemInput) {
systemInput.addEventListener('focus', () => {
if (window.innerWidth < 600) {
isEditingSystemPrompt = true;
systemContainer.classList.add('mobile-edit-mode');
document.body.style.overflow = 'hidden';
}
});
const exitEditMode = () => {
isEditingSystemPrompt = false;
systemContainer.classList.remove('mobile-edit-mode');
document.body.style.overflow = '';
// Einmaliges Auto-Grow nach dem Schließen
systemInput.style.height = "auto";
systemInput.style.height = systemInput.scrollHeight + "px";
};
systemInput.addEventListener('blur', () => {
// Delay, um dem Klick auf den Button Vorrang zu geben
setTimeout(exitEditMode, 200);
});
}

View File

@@ -4,7 +4,7 @@
:root { :root {
/* --- Hell-Modus --- */ /* --- Hell-Modus --- */
--bg-body: #ffffff; --bg-body: #ffffff;
--bg-section-alt: #f8f9fa; --bg-section-alt: #ddddec;
--text-main: #333333; --text-main: #333333;
--text-muted: #666666; --text-muted: #666666;
--header-bg: rgba(255, 255, 255, 0.95); --header-bg: rgba(255, 255, 255, 0.95);
@@ -15,7 +15,7 @@
--border-color: #eeeeee; --border-color: #eeeeee;
/* Hero & Akzente */ /* Hero & Akzente */
--accent: #667eea; --accent: #6072c5;
--accent-text: #ffffff; --accent-text: #ffffff;
--accent-dark: #764ba2; --accent-dark: #764ba2;
--hero-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); --hero-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@@ -42,7 +42,7 @@
--border-color: #2d334a; --border-color: #2d334a;
/* Hero & Akzente (Im Darkmode etwas entspannter) */ /* Hero & Akzente (Im Darkmode etwas entspannter) */
--accent: #39348c; --accent: #6e6abc;
--accent-text: #ffffff; --accent-text: #ffffff;
--accent-dark: #3d4593; --accent-dark: #3d4593;
--hero-gradient: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%); --hero-gradient: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%);
@@ -212,25 +212,13 @@ nav {
} }
.hamburger {
display: none;
flex-direction: column;
gap: 5px;
cursor: pointer;
}
.hamburger span {
display: block;
width: 25px;
height: 3px;
background-color: var(--accent);
border-radius: 3px;
}
/* ========================================== /* ==========================================
3. HERO SECTION 3. HERO SECTION
========================================== */ ========================================== */
.hero { .hero {
min-height: 100vh; min-height: 100vh;
/*height: calc(100vh - 45px);
margin-top: 45px;*/
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -257,6 +245,7 @@ nav {
opacity: 0.9; opacity: 0.9;
} }
/* ========================================== /* ==========================================
4. BUTTONS & INPUTS (Neu gestylt) 4. BUTTONS & INPUTS (Neu gestylt)
========================================== */ ========================================== */
@@ -317,23 +306,7 @@ nav {
margin-top: 2rem; margin-top: 2rem;
} }
/* Eingabefeld (Chat) */
#user-input {
flex: 1;
padding: 12px 16px;
border: 1px solid var(--border-input);
border-radius: 8px;
background: var(--bg-input);
color: var(--text-input);
font-size: 1rem;
transition: all 0.2s ease;
}
#user-input:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
}
/* ========================================== /* ==========================================
5. SECTIONS & CARDS 5. SECTIONS & CARDS
@@ -356,7 +329,7 @@ h2 {
} }
.text { .text {
max-width: 800px; /*max-width: 1200px;*/
margin: 0 auto; margin: 0 auto;
text-align: center; text-align: center;
font-size: 1.1rem; font-size: 1.1rem;
@@ -364,101 +337,8 @@ h2 {
color: var(--text-muted); color: var(--text-muted);
} }
/* Hier ist die wichtige Änderung für das Nebeneinanderstehen */
.projects, .tech-features {
display: grid;
/* Erzeugt so viele Spalten wie nebeneinander passen (mind. 300px breit) */
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin-top: 3rem;
}
.project-card, .tech-card {
background-color: var(--card-bg);
border-radius: 15px;
padding: 2.5rem;
box-shadow: 0 10px 30px var(--card-shadow);
border: 1px solid var(--border-color);
text-align: center;
transition: transform 0.3s ease, background-color 0.3s;
/* Flexbox Korrektur */
display: flex;
flex-direction: column;
justify-content: flex-start; /* Schiebt alles nach oben */
height: 100%; /* Sorgt dafür, dass alle Karten in einer Reihe gleich hoch sind */
}
.project-card h3, .tech-card h3 {
color: var(--accent);
margin-bottom: 1.2rem; /* Abstand zwischen Überschrift und Text */
font-size: 1.5rem;
}
.project-card p, .tech-card p {
color: var(--text-muted);
line-height: 1.6;
margin-bottom: 0; /* Verhindert unnötigen Platz nach unten */
}
.project-card:hover, .tech-card:hover {
transform: translateY(-5px);
}
/* Chat-Container Hintergrund korrigiert */
.chat-container {
max-width: 800px;
margin: 100px auto 20px;
display: flex;
flex-direction: column;
height: calc(100vh - 140px);
background: var(--card-bg); /* Nutzt Card Background Variable */
border-radius: 12px;
box-shadow: 0 10px 25px var(--card-shadow);
border: 1px solid var(--border-color);
overflow: hidden;
}
#chat-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 15px;
}
.message {
max-width: 80%;
padding: 12px 16px;
border-radius: 15px;
line-height: 1.5;
font-size: 0.95rem;
}
.user-message {
align-self: flex-end;
background-color: var(--accent);
color: var(--accent-text);
border-bottom-right-radius: 5px;
}
.ai-message {
align-self: flex-start;
background-color: var(--bg-section-alt);
color: var(--text-main);
border-bottom-left-radius: 5px;
}
.chat-input-area {
padding: 20px;
background-color: var(--card-bg);
border-top: 1px solid var(--border-color);
display: flex;
gap: 10px;
align-items: center;
}
/* ========================================== /* ==========================================
6. FOOTER 6. FOOTER
@@ -486,22 +366,35 @@ footer {
/* ========================================== /* ==========================================
7. RESPONSIVENESS 7. RESPONSIVENESS
========================================== */ ========================================== */
@media (max-width: 950px) { /* --- Standard: Logo kurz ausblenden, lang anzeigen --- */
.hamburger { display: flex; }
.nav-links { /* Standard für Desktop: Beide sichtbar */
position: absolute;
top: 100%; left: 0; width: 100%; .hamburger {
background-color: var(--header-bg); display: none;
flex-direction: column; flex-direction: column;
max-height: 0; gap: 5px;
overflow: hidden; cursor: pointer;
transition: max-height 0.4s ease; }
} .hamburger span {
.nav-links.mobile-open { max-height: 300px; } display: block;
.nav-links li { border-bottom: 1px solid var(--border-color); } width: 25px;
/*.nav-links a { padding: 0.1rem; display: block; }*/ height: 3px;
background-color: var(--accent);
border-radius: 3px;
}
.logo-short { display: none;}
.logo-full { display: inline;}
@media (max-width: 950px) {
.logo-full {display: none;}
.logo-short {display: inline;}
.hero h1 { font-size: 2.2rem; } .hero h1 { font-size: 2.2rem; }
} }

View File

@@ -8,27 +8,6 @@ function toggleHamburger() {
hamburger.classList.toggle('active'); hamburger.classList.toggle('active');
} }
// Initialisierung
document.addEventListener('DOMContentLoaded', () => {
// ... dein bestehender Code ...
const savedTheme = localStorage.getItem('theme') || 'auto';
applyTheme(savedTheme);
// Hamburger Menü schließen bei Klick auf einen Link
const navLinksContainer = document.getElementById('navLinks');
const navLinks = navLinksContainer.querySelectorAll('a');
const hamburger = document.querySelector('.hamburger');
navLinks.forEach(link => {
link.addEventListener('click', () => {
// Prüfen, ob das Menü gerade offen ist
if (navLinksContainer.classList.contains('mobile-open')) {
navLinksContainer.classList.remove('mobile-open');
hamburger.classList.remove('active');
}
});
});
});
/* ========================================== /* ==========================================
DROPDOWN LOGIC (Vereinheitlicht) DROPDOWN LOGIC (Vereinheitlicht)
@@ -119,44 +98,9 @@ function applyTheme(theme) {
} }
} }
async function startDemoChat() {
try {
const response = await fetch('/api/v1/chats/new', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
// WICHTIG: Wenn dein Nginx den Token nicht setzt,
// muss er hier hin: 'Authorization': 'Bearer DEIN_TOKEN'
},
body: JSON.stringify({
"title": "Demo Chat",
"chat": { "model": "arcee-ai/trinity-large-preview:free"}
})
});
if (!response.ok) {
const errorData = await response.json();
console.error('API Fehlerdetails:', errorData);
throw new Error(`Fehler: ${response.status}`);
}
const data = await response.json();
const sessionId = data.id;
// --- DER KORREKTE DYNAMISCHE PFAD ---
// 1. Hole den aktuellen Sprachpfad (z.B. "/de/", "/en/")
// split('/') macht aus "/de/about/" -> ["", "de", "about", ""]
const pathSegments = window.location.pathname.split('/');
const lang = pathSegments[1] || 'de'; // Fallback auf "de", falls kein Pfad da ist
// 2. Leite auf den Pfad MIT Sprache und Session-ID um
// Das ergibt dann z.B. /de/chat/?session=...
window.location.href = `/${lang}/chat/?session=${sessionId}`;
//window.location.href = `/de/chat/?session=${sessionId}`;
} catch (error) {
console.error('Fehler beim Starten:', error);
alert('Demo-Chat konnte nicht gestartet werden.');
}
}

73
static/index.css Normal file
View File

@@ -0,0 +1,73 @@
/* Hier ist die wichtige Änderung für das Nebeneinanderstehen */
.projects, .tech-features {
display: grid;
/* Erzeugt so viele Spalten wie nebeneinander passen (mind. 300px breit) */
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin-top: 3rem;
}
.project-card, .tech-card {
background-color: var(--card-bg);
border-radius: 15px;
padding: 2.5rem;
box-shadow: 0 10px 30px var(--card-shadow);
border: 1px solid var(--border-color);
text-align: center;
transition: transform 0.3s ease, background-color 0.3s;
/* Flexbox Korrektur */
display: flex;
flex-direction: column;
justify-content: flex-start; /* Schiebt alles nach oben */
height: 100%; /* Sorgt dafür, dass alle Karten in einer Reihe gleich hoch sind */
}
.project-card h3, .tech-card h3 {
color: var(--accent);
margin-bottom: 1.2rem; /* Abstand zwischen Überschrift und Text */
font-size: 1.5rem;
}
.project-card p, .tech-card p {
color: var(--text-muted);
line-height: 1.6;
margin-bottom: 0; /* Verhindert unnötigen Platz nach unten */
}
.project-card:hover, .tech-card:hover {
transform: translateY(-5px);
}
@media (max-width: 950px) {
.hamburger {
display: flex !important; /* Hamburger nur auf Chat-Mobile zeigen */
}
.nav-links {
position: absolute;
top: 100%; left: 0; width: 100%;
background-color: var(--header-bg);
flex-direction: column;
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease;
}
.nav-links li { border-bottom: 1px solid var(--border-color); }
.nav-links.mobile-open {
display: flex !important;
position: absolute;
max-height: 300px;
top: 100%;
right: 0;
background: var(--header-bg);
width: 200px;
flex-direction: column;
box-shadow: 0 5px 15px var(--card-shadow);
}
}

72
static/index.js Normal file
View File

@@ -0,0 +1,72 @@
/*
async function startDemoChat() {
try {
const response = await fetch('/api/v1/chats/new', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
// WICHTIG: Wenn dein Nginx den Token nicht setzt,
// muss er hier hin: 'Authorization': 'Bearer DEIN_TOKEN'
},
body: JSON.stringify({
"title": "Demo Chat",
"chat": {
//"title": "Neuer Chat",
//"models": ["trinity-test"], // WICHTIG: Es ist ein Array!
//"history": { "messages": {}, "children": {} }
"model":
//"arcee-ai/trinity-large-preview:free"
"trinity-test"
}
})
});
if (!response.ok) {
const errorData = await response.json();
console.error('API Fehlerdetails:', errorData);
throw new Error(`Fehler: ${response.status}`);
}
const data = await response.json();
const sessionId = data.id;
// --- DER KORREKTE DYNAMISCHE PFAD ---
// 1. Hole den aktuellen Sprachpfad (z.B. "/de/", "/en/")
// split('/') macht aus "/de/about/" -> ["", "de", "about", ""]
const pathSegments = window.location.pathname.split('/');
const lang = pathSegments[1] || 'de'; // Fallback auf "de", falls kein Pfad da ist
// 2. Leite auf den Pfad MIT Sprache und Session-ID um
// Das ergibt dann z.B. /de/chat/?session=...
window.location.href = `/${lang}/chat/?session=${sessionId}`;
//window.location.href = `/de/chat/?session=${sessionId}`;
} catch (error) {
console.error('Fehler beim Starten:', error);
alert('Demo-Chat konnte nicht gestartet werden.');
}
}
*/
// Initialisierung
document.addEventListener('DOMContentLoaded', () => {
// ... dein bestehender Code ...
const savedTheme = localStorage.getItem('theme') || 'auto';
applyTheme(savedTheme);
// Hamburger Menü schließen bei Klick auf einen Link
const navLinksContainer = document.getElementById('navLinks');
const navLinks = navLinksContainer.querySelectorAll('a');
const hamburger = document.querySelector('.hamburger');
navLinks.forEach(link => {
link.addEventListener('click', () => {
// Prüfen, ob das Menü gerade offen ist
if (navLinksContainer.classList.contains('mobile-open')) {
navLinksContainer.classList.remove('mobile-open');
hamburger.classList.remove('active');
}
});
});
});