Meine KI - Smart & Modern
by BlazeKoala99833 lines20.4 KB
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Meine KI - Smart & Modern</title>
<!-- Externe Bibliotheken für Markdown und Syntax Highlighting -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<style>
:root {
--bg-main: #09090b;
--bg-surface: #121217;
--bg-header: #121217;
--bg-input: #18181f;
--border-color: #27272a;
--accent: #8b5cf6;
--accent-hover: #7c3aed;
--cyan: #06b6d4;
--text-main: #f4f4f5;
--text-muted: #a1a1aa;
}
*{box-sizing:border-box;margin:0;padding:0}
body{
height:100vh;
background:var(--bg-main);
color:var(--text-main);
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
overflow:hidden;
}
#app{
display:flex;
height:100vh;
flex-direction:row;
}
/* SIDEBAR */
aside{
width:280px;
background:var(--bg-surface);
border-right:1px solid var(--border-color);
display:flex;
flex-direction:column;
padding:16px;
transition: transform 0.3s ease;
z-index: 45;
}
aside h2{
font-size:14px;
margin-bottom:12px;
color:#e9d5ff;
display:flex;
align-items:center;
justify-content:space-between;
}
.memory-add-row {
display: flex;
gap: 6px;
margin-bottom: 12px;
}
.memory-add-row input {
flex: 1;
background: var(--bg-input);
border: 1px solid var(--border-color);
padding: 8px 10px;
border-radius: 6px;
color: white;
font-size: 13px;
outline: none;
transition: border-color 0.2s;
}
.memory-add-row input:focus {
border-color: var(--accent);
}
.memory-add-row button {
background: var(--accent);
color: white;
border: none;
padding: 0 12px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
transition: background 0.2s;
}
.memory-add-row button:hover {
background: var(--accent-hover);
}
#memoryList{
flex:1;
overflow-y:auto;
list-style:none;
display:flex;
flex-direction:column;
gap:6px;
margin-bottom:12px;
}
.memory-item{
background:var(--bg-input);
padding:8px 10px;
border-radius:6px;
font-size:13px;
color:#d4d4d8;
border:1px solid var(--border-color);
display:flex;
justify-content:space-between;
align-items:center;
word-break:break-word;
}
.memory-item button{
background:transparent;
color:#f87171;
padding:2px 6px;
font-size:12px;
cursor:pointer;
border-radius:4px;
border:0;
}
.memory-item button:hover{
background:rgba(248,113,113,0.1);
}
.memory-hint{
font-size:11px;
color:var(--text-muted);
line-height:1.4;
}
/* HAUPTBEREICH */
.main-container{
flex:1;
display:flex;
flex-direction:column;
height:100vh;
background:var(--bg-main);
position:relative;
}
header{
height:60px;
padding:0 20px;
display:flex;
align-items:center;
justify-content:space-between;
background:var(--bg-header);
border-bottom:1px solid var(--border-color);
}
.header-left {
display: flex;
align-items: center;
gap: 10px;
}
header h1{
font-size:16px;
font-weight:600;
}
.header-right {
display: flex;
align-items: center;
gap: 10px;
}
.menu-toggle {
background: transparent;
border: 1px solid var(--border-color);
color: #e9d5ff;
padding: 6px 10px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
display: none;
}
.menu-toggle:hover {
background: rgba(139, 92, 246, 0.1);
}
.online{
display:flex;
align-items:center;
gap:6px;
color:#4ade80;
font-size:12px;
background:rgba(74,222,128,0.1);
padding:4px 10px;
border-radius:20px;
border:1px solid rgba(74,222,128,0.2);
}
.clear-btn {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-muted);
padding: 6px 10px;
border-radius: 6px;
font-size: 12px;
cursor: pointer;
transition: all 0.2s;
}
.clear-btn:hover {
background: rgba(255,255,255,0.05);
color: white;
}
#chat{
flex:1;
overflow-y:auto;
padding:24px;
display:flex;
flex-direction:column;
gap:16px;
scroll-behavior: smooth;
}
.message{
max-width:800px;
padding:14px 18px;
border-radius:12px;
line-height:1.5;
font-size:14px;
position: relative;
animation: fadeIn 0.25s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
.message p { margin-bottom: 6px; }
.message p:last-child { margin-bottom: 0; }
.message ul, .message ol { margin-left: 20px; margin-bottom: 6px; }
.message pre { background: #09090b; padding: 10px; border-radius: 6px; margin: 8px 0; overflow-x: auto; border: 1px solid var(--border-color); position: relative; }
.message code { font-family: monospace; font-size: 12.5px; }
/* Copy Code Button */
.copy-code-btn {
position: absolute;
top: 6px;
right: 6px;
background: #27272a;
color: #d4d4d8;
border: 1px solid var(--border-color);
padding: 2px 6px;
font-size: 11px;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
}
.copy-code-btn:hover {
background: var(--accent);
color: white;
}
.user{
margin-left:auto;
background:var(--accent);
color:white;
border-bottom-right-radius:2px;
}
.ai{
margin-right:auto;
background:var(--bg-surface);
color:var(--text-main);
border:1px solid var(--border-color);
border-bottom-left-radius:2px;
}
.ai img, .message img{
display:block;
width:100%;
max-width:500px;
margin-top:10px;
border-radius:8px;
border:1px solid var(--border-color);
}
/* TYPING INDICATOR */
.typing-dots {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 0;
}
.typing-dots span {
width: 6px;
height: 6px;
background: var(--text-muted);
border-radius: 50%;
animation: bounce 1.4s infinite ease-in-out both;
}
.typing-dots span:nth-child(1) { animation-delay: -0.32s; }
.typing-dots span:nth-child(2) { animation-delay: -0.16s; }
@keyframes bounce {
0%, 80%, 100% { transform: scale(0); }
40% { transform: scale(1.0); }
}
/* CHAT VORSCHAU */
.chat-file-preview {
display: flex;
align-items: center;
gap: 8px;
background: rgba(255,255,255,0.05);
padding: 6px 10px;
border-radius: 6px;
margin-bottom: 8px;
font-size: 12px;
border: 1px solid rgba(255,255,255,0.08);
}
.chat-file-preview img {
width: 28px;
height: 28px;
object-fit: cover;
border-radius: 4px;
margin: 0 !important;
}
#bottom{
padding:16px 24px;
background:var(--bg-header);
border-top:1px solid var(--border-color);
}
#inputBox{
max-width:850px;
margin:auto;
display:flex;
flex-direction:column;
background:var(--bg-input);
padding:8px;
border-radius:12px;
border:1px solid var(--border-color);
gap:6px;
}
.input-row{
display:flex;
gap:6px;
align-items:center;
}
#input{
flex:1;
min-width:0;
padding:8px 10px;
border:0;
outline:0;
background:transparent;
color:white;
font-size:14px;
}
#input::placeholder{
color:var(--text-muted);
}
button.action-btn{
border:0;
border-radius:8px;
padding:8px 14px;
background:var(--accent);
color:white;
cursor:pointer;
font-size:13px;
font-weight:600;
transition:background 0.2s;
display:flex;
align-items:center;
gap:6px;
white-space:nowrap;
}
button.action-btn:hover{
background:var(--accent-hover);
}
#imageButton{
background:#0891b2;
}
#imageButton:hover{
background:var(--cyan);
}
#fileButton{
background:#27272a;
color: #c084fc;
padding: 8px 10px;
}
#fileButton:hover{
background:#3f3f46;
}
/* ANGEHÄNGTE DATEI */
#attachmentArea {
display: none;
flex-wrap: wrap;
gap: 6px;
padding: 4px 6px;
}
.attachment-chip {
display: flex;
align-items: center;
gap: 6px;
background: #27272a;
padding: 4px 8px;
border-radius: 6px;
font-size: 12px;
color: #f4f4f5;
border: 1px solid var(--border-color);
}
.attachment-chip button {
background: none;
border: none;
color: #f87171;
cursor: pointer;
font-weight: bold;
}
/* DRAG & DROP OVERLAY */
#dropZoneOverlay {
position: absolute;
inset: 0;
background: rgba(9, 9, 11, 0.85);
border: 2px dashed var(--accent);
z-index: 50;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
color: #e9d5ff;
font-size: 16px;
font-weight: 500;
backdrop-filter: blur(4px);
}
/* Responsive */
@media (max-width: 768px) {
aside {
position: absolute;
height: 100%;
transform: translateX(-100%);
}
aside.open {
transform: translateX(0);
}
.menu-toggle {
display: block;
}
}
/* Scrollbar */
::-webkit-scrollbar{
width:5px;
height:5px;
}
::-webkit-scrollbar-track{
background:transparent;
}
::-webkit-scrollbar-thumb{
background:var(--border-color);
border-radius:10px;
}
::-webkit-scrollbar-thumb:hover{
background:#3f3f46;
}
</style>
</head>
<body>
<div id="app">
<aside id="sidebar">
<h2>
<span>🧠 Gedächtnis</span>
<button class="menu-toggle" onclick="toggleSidebar()" style="display:inline-block; font-size:11px; padding:2px 5px;">✕</button>
</h2>
<div class="memory-add-row">
<input type="text" id="manualMemoryInput" placeholder="Erinnerung hinzufügen..." onkeydown="if(event.key==='Enter')addManualMemory()">
<button onclick="addManualMemory()">+</button>
</div>
<ul id="memoryList"></ul>
<div class="memory-hint">
Hinterlege wichtige Infos oder Vorlieben für zukünftige Antworten.
</div>
</aside>
<div class="main-container" id="mainContainer">
<div id="dropZoneOverlay">
📁 Datei hier ablegen...
</div>
<header>
<div class="header-left">
<button class="menu-toggle" onclick="toggleSidebar()">☰</button>
<h1>🤖 Meine KI</h1>
</div>
<div class="header-right">
<button class="clear-btn" onclick="clearChat()">Chat leeren</button>
<span class="online">● Online</span>
</div>
</header>
<main id="chat">
<div class="message ai">
Hey! 👋 Ich bin deine aktualisierte KI. Wie kann ich dir heute weiterhelfen?
</div>
</main>
<div id="bottom">
<div id="inputBox">
<div id="attachmentArea"></div>
<div class="input-row">
<input type="file" id="fileInput" style="display:none" onchange="handleFileSelect(event)" multiple>
<button class="action-btn" id="fileButton" onclick="document.getElementById('fileInput').click()" title="Datei hochladen">
📎
</button>
<input
id="input"
type="text"
placeholder="Nachricht eingeben..."
autocomplete="off"
>
<button class="action-btn" onclick="sendMessage()">
Senden
</button>
<button
class="action-btn"
id="imageButton"
onclick="createImage()"
title="Bild generieren"
>
🖼️
</button>
</div>
</div>
</div>
</div>
</div>
<script>
marked.setOptions({ breaks: true, gfm: true });
document.addEventListener("DOMContentLoaded", () => {
document.getElementById("input").focus();
});
function toggleSidebar() {
document.getElementById("sidebar").classList.toggle("open");
}
let memories = JSON.parse(localStorage.getItem("ai_memories")) || [];
function renderMemories() {
const list = document.getElementById("memoryList");
list.innerHTML = "";
if (memories.length === 0) {
list.innerHTML = `<li style="color:var(--text-muted); font-size:12px; text-align:center; margin-top:10px;">Keine Erinnerungen.</li>`;
return;
}
memories.forEach((mem, index) => {
const li = document.createElement("li");
li.className = "memory-item";
li.innerHTML = `<span>${escapeHTML(mem)}</span><button onclick="deleteMemory(${index})">✕</button>`;
list.appendChild(li);
});
}
function addMemory(text) {
if (text && !memories.includes(text)) {
memories.push(text);
localStorage.setItem("ai_memories", JSON.stringify(memories));
renderMemories();
}
}
function addManualMemory() {
const inputField = document.getElementById("manualMemoryInput");
const val = inputField.value.trim();
if (val) {
addMemory(val);
inputField.value = "";
}
}
function deleteMemory(index) {
memories.splice(index, 1);
localStorage.setItem("ai_memories", JSON.stringify(memories));
renderMemories();
}
function escapeHTML(str) {
return str.replace(/[&<>'"]/g, tag => ({ '&': '&', '<': '<', '>': '>', "'": ''', '"': '"' }[tag] || tag));
}
renderMemories();
let attachedFiles = [];
const mainContainer = document.getElementById("mainContainer");
const dropZoneOverlay = document.getElementById("dropZoneOverlay");
['dragenter', 'dragover'].forEach(eventName => {
mainContainer.addEventListener(eventName, (e) => {
e.preventDefault(); e.stopPropagation();
dropZoneOverlay.style.display = "flex";
}, false);
});
['dragleave', 'drop'].forEach(eventName => {
mainContainer.addEventListener(eventName, (e) => {
e.preventDefault(); e.stopPropagation();
if (eventName === 'drop') handleFiles(e.dataTransfer.files);
dropZoneOverlay.style.display = "none";
}, false);
});
function handleFileSelect(e) {
handleFiles(e.target.files);
e.target.value = "";
}
function handleFiles(files) {
for (let file of files) {
const reader = new FileReader();
reader.onload = function(event) {
attachedFiles.push({ name: file.name, type: file.type, size: file.size, content: event.target.result });
renderAttachments();
};
if (file.type.startsWith("image/") || file.type.includes("pdf")) {
reader.readAsDataURL(file);
} else {
reader.readAsText(file);
}
}
}
function renderAttachments() {
const area = document.getElementById("attachmentArea");
area.innerHTML = "";
if (attachedFiles.length === 0) {
area.style.display = "none";
return;
}
area.style.display = "flex";
attachedFiles.forEach((file, index) => {
const chip = document.createElement("div");
chip.className = "attachment-chip";
chip.innerHTML = `<span>📄 ${escapeHTML(file.name)}</span><button onclick="removeAttachment(${index})">✕</button>`;
area.appendChild(chip);
});
}
function removeAttachment(index) {
attachedFiles.splice(index, 1);
renderAttachments();
}
const input = document.getElementById("input");
const chat = document.getElementById("chat");
let conversation = [];
input.addEventListener("keydown", function(e){
if(e.key === "Enter" && !e.shiftKey){
e.preventDefault();
sendMessage();
}
});
function clearChat() {
if(confirm("Chat wirklich leeren?")) {
chat.innerHTML = `<div class="message ai">Hey! 👋 Chat zurückgesetzt.</div>`;
conversation = [];
}
}
function addMessage(text, type, files = [], isMarkdown = false){
const div = document.createElement("div");
div.className = "message " + type;
if (files && files.length > 0) {
files.forEach(f => {
const filePreview = document.createElement("div");
filePreview.className = "chat-file-preview";
if (f.type && f.type.startsWith("image/")) {
filePreview.innerHTML = `<img src="${f.content}" alt="Bild"><span>${escapeHTML(f.name)}</span>`;
} else {
filePreview.innerHTML = `<span>📎 ${escapeHTML(f.name)}</span>`;
}
div.appendChild(filePreview);
});
}
const textSpan = document.createElement("div");
if (isMarkdown) {
textSpan.innerHTML = marked.parse(text);
processCodeBlocks(textSpan);
} else {
textSpan.textContent = text;
}
div.appendChild(textSpan);
chat.appendChild(div);
chat.scrollTop = chat.scrollHeight;
return div;
}
function processCodeBlocks(container) {
container.querySelectorAll('pre code').forEach((block) => {
hljs.highlightElement(block);
const pre = block.parentElement;
if (!pre.querySelector('.copy-code-btn')) {
const copyBtn = document.createElement('button');
copyBtn.className = 'copy-code-btn';
copyBtn.textContent = 'Kopieren';
copyBtn.onclick = () => {
navigator.clipboard.writeText(block.textContent).then(() => {
copyBtn.textContent = 'Kopiert!';
setTimeout(() => copyBtn.textContent = 'Kopieren', 2000);
});
};
pre.appendChild(copyBtn);
}
});
}
async function sendMessage(){
const text = input.value.trim();
if(!text && attachedFiles.length === 0) return;
const currentFiles = [...attachedFiles];
addMessage(text || "Dateien gesendet:", "user", currentFiles);
input.value = "";
attachedFiles = [];
renderAttachments();
const answerBox = addMessage('', "ai");
answerBox.innerHTML = '<div class="typing-dots"><span></span><span></span><span></span></div>';
let systemInstruction = "Du bist eine smarte, hilfsbereite und präzise KI.";
if (memories.length > 0) {
systemInstruction += "\n\nBekannte Fakten:\n- " + memories.join("\n- ");
}
let enhancedText = text;
if (currentFiles.length > 0) {
enhancedText += "\n\n[Anhänge:]\n";
currentFiles.forEach(f => {
enhancedText += `--- ${f.name} ---\n${f.content}\n\n`;
});
}
conversation.push({ role: "user", content: enhancedText });
try{
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages: [{ role: "system", content: systemInstruction }, ...conversation] })
});
const data = await response.json();
if(!response.ok) throw new Error(data.error || "KI-Fehler");
answerBox.innerHTML = "";
const parsedContent = document.createElement("div");
parsedContent.innerHTML = marked.parse(data.answer);
processCodeBlocks(parsedContent);
answerBox.appendChild(parsedContent);
conversation.push({ role: "assistant", content: data.answer });
chat.scrollTop = chat.scrollHeight;
}catch(error){
answerBox.textContent = "❌ Fehler:\n\n" + error.message;
}
}
async function createImage(){
let prompt = input.value.trim() || window.prompt("Was soll gezeichnet werden?");
if(!prompt) return;
addMessage("🖼️ " + prompt, "user");
input.value = "";
const imageBox = addMessage('', "ai");
imageBox.innerHTML = '<div class="typing-dots"><span></span><span></span><span></span></div>';
try{
const response = await fetch("/api/image", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt })
});
const data = await response.json();
if(!response.ok) throw new Error(data.error || "Fehler beim Generieren.");
imageBox.textContent = "🎨 Fertig!";
const img = document.createElement("img");
img.src = data.image;
img.alt = prompt;
imageBox.appendChild(img);
chat.scrollTop = chat.scrollHeight;
}catch(error){
imageBox.textContent = "❌ Fehler:\n\n" + error.message;
}
}
</script>
</body>
</html>Game Source: Meine KI - Smart & Modern
Creator: BlazeKoala99
Libraries: none
Complexity: complex (833 lines, 20.4 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: meine-ki-smart-modern-blazekoala99" to link back to the original. Then publish at arcadelab.ai/publish.