NeonChat v1.0 — Lokaler RP-Chatbot
Features: - FastAPI Backend + Ollama Integration - Character System (JSON-basiert, einfach zu erstellen) - Kurzzeitgedächtnis (SQLite, letzte 20 Nachrichten) - Langzeitgedächtnis (automatische Zusammenfassungen alle 20 Nachrichten) - Moderne Web-UI (dunkles Theme, Neon-Accents) - Character-Erstellungs-Seite im Browser - Beispiel-Character: Mara (Barista, zynisch, warmherzig) - Unzensiert (lokal, keine Cloud) - Gedächtnis-Panel (Ein- und Ausblenden) - Vergessen-Funktion (Gedächtnis löschen)
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>NeonChat — Neuer Charakter</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: 'Segoe UI', system-ui, sans-serif; background: #0a0a0f; color: #e0e0e8; min-height: 100vh; }
|
||||
.container { max-width: 700px; margin: 0 auto; padding: 30px 20px; }
|
||||
h1 { font-size: 1.8rem; margin-bottom: 6px; background: linear-gradient(135deg, #ff006e, #8338ec); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
|
||||
.subtitle { color: #6b6b80; margin-bottom: 24px; font-size: 0.9rem; }
|
||||
.form-group { margin-bottom: 16px; }
|
||||
label { display: block; font-size: 0.85rem; color: #9b9bb0; margin-bottom: 6px; font-weight: 600; }
|
||||
label .hint { color: #4b4b60; font-weight: 400; font-size: 0.8rem; }
|
||||
input, textarea, select { width: 100%; background: #15151f; border: 1px solid #252535; border-radius: 10px; padding: 10px 14px; color: #e0e0e8; font-size: 0.9rem; font-family: inherit; outline: none; transition: border 0.15s; }
|
||||
input:focus, textarea:focus, select:focus { border-color: #8338ec; }
|
||||
textarea { resize: vertical; min-height: 60px; line-height: 1.5; }
|
||||
.row { display: flex; gap: 12px; }
|
||||
.row > div { flex: 1; }
|
||||
.btn { padding: 12px 28px; border-radius: 10px; border: none; background: linear-gradient(135deg, #8338ec, #ff006e); color: white; font-size: 1rem; cursor: pointer; font-weight: 600; transition: opacity 0.15s; }
|
||||
.btn:hover { opacity: 0.9; }
|
||||
.btn-back { background: transparent; border: 1px solid #252535; color: #6b6b80; margin-right: 10px; }
|
||||
#models { margin-top: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>✦ Neuer Charakter</h1>
|
||||
<p class="subtitle">Definiere Persönlichkeit, Verhalten und Hintergrund. Der Bot bleibt immer in Rolle.</p>
|
||||
|
||||
<form id="createForm">
|
||||
<div class="row">
|
||||
<div class="form-group">
|
||||
<label>Name</label>
|
||||
<input type="text" id="name" placeholder="z.B. Mara" required>
|
||||
</div>
|
||||
<div class="form-group" style="max-width: 80px;">
|
||||
<label>Avatar</label>
|
||||
<input type="text" id="avatar" value="👤" maxlength="4" style="text-align: center; font-size: 1.5rem;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Kurze Beschreibung <span class="hint">(für die Übersicht)</span></label>
|
||||
<input type="text" id="description" placeholder="z.B. Barista, 28, zynisch aber warmherzig">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Persönlichkeit <span class="hint">(wie ist der Charakter?)</span></label>
|
||||
<textarea id="personality" placeholder="z.B. Trocken, sarkastisch, aber loyal. Hilfsbereit auf ihre Art. Zeigt Gefühle selten direkt."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Hintergrund <span class="hint">(Wer ist der Charakter?)</span></label>
|
||||
<textarea id="background" placeholder="z.B. Arbeitet seit 5 Jahren in einem Café. Hat mal Kunst studiert, abgebrochen. Lebt allein mit einer Katze."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Verhalten <span class="hint">(wie verhält sich der Charakter?)</span></label>
|
||||
<textarea id="behavior" placeholder="z.B. Flucht in Wortwitze wenn nervös. Klopft auf den Tresen. Unterbricht nicht. Stellt Gegenfragen."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Sprachstil <span class="hint">(wie spricht der Charakter?)</span></label>
|
||||
<textarea id="tone" placeholder="z.B. Umgangssprachlich, 'ne' statt 'nicht', 'mal' statt 'einmal', flucht gelegentlich, kurze Sätze"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Szenario <span class="hint">(optional — wo spielt das Gespräch?)</span></label>
|
||||
<input type="text" id="scenario" placeholder="z.B. Du sitzt in einem kleinen Café, es regnet draußen.">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>NSFW / Soziale Regeln <span class="hint">(optional)</span></label>
|
||||
<textarea id="nsfw" placeholder="z.B. Keine Einschränkungen. Kann über alles sprechen. Flirten erwünscht."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Begrüßung <span class="hint">(erste Nachricht vom Bot)</span></label>
|
||||
<textarea id="greeting" placeholder="z.B. *schaut auf als du das Café betrittst* Na, wieder da? Der übliche?"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="form-group">
|
||||
<label>Modell <span class="hint">(Ollama)</span></label>
|
||||
<select id="model">
|
||||
<option value="">Default</option>
|
||||
</select>
|
||||
<div id="models" style="font-size: 0.8rem; color: #4b4b60;"></div>
|
||||
</div>
|
||||
<div class="form-group" style="max-width: 100px;">
|
||||
<label>Temperatur <span class="hint">(Kreativität)</span></label>
|
||||
<input type="number" id="temperature" value="0.8" min="0.1" max="2.0" step="0.1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<button type="button" class="btn btn-back" onclick="location.href='/'">← Abbrechen</button>
|
||||
<button type="submit" class="btn">Charakter erstellen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Load models
|
||||
fetch('/api/models').then(r => r.json()).then(data => {
|
||||
const select = document.getElementById('model');
|
||||
if (data.models) {
|
||||
data.models.forEach(m => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = m; opt.textContent = m;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
}
|
||||
if (data.error) document.getElementById('models').textContent = '⚠️ ' + data.error;
|
||||
});
|
||||
|
||||
document.getElementById('createForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
name: document.getElementById('name').value,
|
||||
avatar: document.getElementById('avatar').value,
|
||||
description: document.getElementById('description').value,
|
||||
personality: document.getElementById('personality').value,
|
||||
background: document.getElementById('background').value,
|
||||
behavior: document.getElementById('behavior').value,
|
||||
tone: document.getElementById('tone').value,
|
||||
scenario: document.getElementById('scenario').value,
|
||||
nsfw: document.getElementById('nsfw').value,
|
||||
greeting: document.getElementById('greeting').value,
|
||||
model: document.getElementById('model').value,
|
||||
temperature: parseFloat(document.getElementById('temperature').value),
|
||||
};
|
||||
const resp = await fetch('/api/character/create', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
const result = await resp.json();
|
||||
if (result.status === 'ok') {
|
||||
location.href = '/chat/' + encodeURIComponent(result.character);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user