202 lines
6.7 KiB
HTML
202 lines
6.7 KiB
HTML
{% extends "home/base_home.html" %}
|
|
|
|
{% block title %}Crew - {{ deployment.home.hero.title }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<main class="container">
|
|
<hgroup>
|
|
<h1>{{ t.crew.title }}</h1>
|
|
<p>{{ t.crew.subtitle }}</p>
|
|
</hgroup>
|
|
|
|
<div class="crew-grid">
|
|
{% for character in characters %}
|
|
<div class="character-card" onclick="showCharacter('{{ character.id }}')">
|
|
<div class="icon">{{ character.icon }}</div>
|
|
<h3>{{ character.name }}</h3>
|
|
<p>{{ character.short }}</p>
|
|
</div>
|
|
|
|
<!-- Dialog for this character -->
|
|
<dialog id="dialog-{{ character.id }}">
|
|
<article>
|
|
<header>
|
|
<button aria-label="Close" rel="prev" onclick="closeCharacter('{{ character.id }}')"></button>
|
|
<h2>{{ character.icon }} {{ character.name }}</h2>
|
|
</header>
|
|
<p>{{ character.description }}</p>
|
|
|
|
{% if character.id in ['eule', 'fox', 'bugsy'] %}
|
|
<!-- Chat Interface for Eule, FunkFox and Bugsy -->
|
|
<div class="chat-container" style="margin-top: 1rem;">
|
|
<div id="chat-history-{{ character.id }}" class="chat-history" style="max-height: 300px; overflow-y: auto; padding: 1rem; background: rgba(0,0,0,0.1); border-radius: 0.5rem; margin-bottom: 1rem;">
|
|
<p style="text-align: center; color: #888;"><small>Stelle mir eine Frage...</small></p>
|
|
</div>
|
|
|
|
<form id="chat-form-{{ character.id }}" onsubmit="sendMessage(event, '{{ character.id }}'); return false;">
|
|
<input
|
|
type="text"
|
|
id="chat-input-{{ character.id }}"
|
|
placeholder="{% if character.id == 'eule' %}Deine Frage an die Krümeleule...{% elif character.id == 'fox' %}Deine Frage an FunkFox...{% elif character.id == 'bugsy' %}Deine Frage an Bugsy...{% else %}Deine Frage...{% endif %}"
|
|
style="width: 100%; color: #fff; background: rgba(255,255,255,0.1); padding: 0.75rem; border: 1px solid rgba(255,255,255,0.2); border-radius: 0.25rem; margin-bottom: 0.5rem;"
|
|
autocomplete="off"
|
|
required
|
|
/>
|
|
<div style="text-align: right;">
|
|
<button
|
|
type="submit"
|
|
id="chat-submit-{{ character.id }}"
|
|
style="padding: 0.5rem 1.5rem; font-size: 0.875rem;"
|
|
>
|
|
Senden
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div id="chat-status-{{ character.id }}" style="margin-top: 0.5rem; text-align: center; min-height: 1.5rem;">
|
|
<!-- Status messages appear here -->
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<footer>
|
|
<small>{{ t.crew.tags_label }}
|
|
{% for tag in character.tags %}
|
|
<code>#{{ tag }}</code>{% if not loop.last %}, {% endif %}
|
|
{% endfor %}
|
|
</small>
|
|
</footer>
|
|
</article>
|
|
</dialog>
|
|
{% endfor %}
|
|
</div>
|
|
</main>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
function showCharacter(id) {
|
|
const dialog = document.getElementById('dialog-' + id);
|
|
dialog.showModal();
|
|
|
|
// Focus input field for chat-enabled characters
|
|
if (id === 'eule' || id === 'fox' || id === 'bugsy') {
|
|
setTimeout(() => {
|
|
const input = document.getElementById('chat-input-' + id);
|
|
if (input) {
|
|
input.focus();
|
|
}
|
|
}, 100);
|
|
}
|
|
}
|
|
|
|
function closeCharacter(id) {
|
|
document.getElementById('dialog-' + id).close();
|
|
}
|
|
|
|
async function sendMessage(event, characterId) {
|
|
event.preventDefault();
|
|
|
|
const inputEl = document.getElementById('chat-input-' + characterId);
|
|
const historyEl = document.getElementById('chat-history-' + characterId);
|
|
const statusEl = document.getElementById('chat-status-' + characterId);
|
|
const submitBtn = document.getElementById('chat-submit-' + characterId);
|
|
|
|
const question = inputEl.value.trim();
|
|
if (!question) return;
|
|
|
|
// Disable input while processing
|
|
inputEl.disabled = true;
|
|
submitBtn.disabled = true;
|
|
const statusMessages = {
|
|
'eule': '🦉 Die Eule lauscht...',
|
|
'fox': '🦊 FunkFox droppt den Beat...',
|
|
'bugsy': '🐞 Bugsy analysiert...'
|
|
};
|
|
statusEl.innerHTML = '<small style="color: #888;">' + (statusMessages[characterId] || 'Denkt nach...') + '</small>';
|
|
|
|
// Add user message to history
|
|
const userMsg = document.createElement('div');
|
|
userMsg.style.cssText = 'margin-bottom: 0.5rem; padding: 0.5rem; background: rgba(16,185,129,0.1); border-radius: 0.25rem; text-align: right;';
|
|
userMsg.innerHTML = '<strong>Du:</strong> ' + escapeHtml(question);
|
|
historyEl.appendChild(userMsg);
|
|
|
|
// Clear welcome message if present
|
|
if (historyEl.querySelector('p')) {
|
|
const welcomeMsg = historyEl.querySelector('p');
|
|
if (welcomeMsg.textContent.includes('Stelle mir eine Frage')) {
|
|
welcomeMsg.remove();
|
|
}
|
|
}
|
|
|
|
// Scroll to bottom
|
|
historyEl.scrollTop = historyEl.scrollHeight;
|
|
|
|
// Clear input
|
|
inputEl.value = '';
|
|
|
|
try {
|
|
// Call API
|
|
const response = await fetch('/api/chat', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
character_id: characterId,
|
|
question: question,
|
|
lang: '{{ lang }}'
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('API request failed: ' + response.status);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
// Add assistant message to history
|
|
const characterNames = {
|
|
'eule': '🦉 Krümeleule',
|
|
'fox': '🦊 FunkFox',
|
|
'bugsy': '🐞 Bugsy'
|
|
};
|
|
const assistantMsg = document.createElement('div');
|
|
assistantMsg.style.cssText = 'margin-bottom: 0.5rem; padding: 0.5rem; background: rgba(255,255,255,0.05); border-radius: 0.25rem;';
|
|
assistantMsg.innerHTML = '<strong>' + (characterNames[characterId] || characterId) + ':</strong><br>' + escapeHtml(data.answer);
|
|
|
|
// Add sources if available
|
|
if (data.sources && data.sources.length > 0) {
|
|
const sourcesText = document.createElement('small');
|
|
sourcesText.style.cssText = 'color: #888; display: block; margin-top: 0.5rem;';
|
|
sourcesText.innerHTML = '📚 Quellen: ' + data.sources.length + ' Dokumente';
|
|
assistantMsg.appendChild(sourcesText);
|
|
}
|
|
|
|
historyEl.appendChild(assistantMsg);
|
|
|
|
// Scroll to bottom
|
|
historyEl.scrollTop = historyEl.scrollHeight;
|
|
|
|
// Clear status
|
|
statusEl.innerHTML = '';
|
|
|
|
} catch (error) {
|
|
console.error('Chat error:', error);
|
|
statusEl.innerHTML = '<small style="color: #f87171;">❌ Fehler: ' + escapeHtml(error.message) + '</small>';
|
|
} finally {
|
|
// Re-enable input
|
|
inputEl.disabled = false;
|
|
submitBtn.disabled = false;
|
|
inputEl.focus();
|
|
}
|
|
}
|
|
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
</script>
|
|
{% endblock %}
|