|
|
| Zeile 1: |
Zeile 1: |
| <includeonly>
| | /* Overlay-Container mit responsive Hintergrundbild */ |
| | |
| <div id="chat-widget">
| |
| <div id="chat-messages"></div>
| |
| <div id="chat-sources-panel"></div>
| |
| <form id="chat-form">
| |
| <input type="text" id="chat-input" placeholder="Stelle eine Frage über Münster …" autocomplete="off" />
| |
| <button type="submit" id="chat-send">Fragen</button>
| |
| </form>
| |
| <div id="chat-footer">
| |
| <span id="chat-status"></span>
| |
| <button id="chat-new" type="button">Neue Unterhaltung</button>
| |
| </div>
| |
| </div>
| |
| | |
| <style>
| |
| #chat-widget {
| |
| max-width: 800px;
| |
| margin: 0 auto;
| |
| font-family: -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
| |
| color: #212529;
| |
| display: flex;
| |
| flex-direction: column;
| |
| | |
| .overlay-container { | | .overlay-container { |
| position: relative; | | position: relative; |
| width: 100%; | | width: 100%; |
| display: inline-block; | | min-height: 400px; |
| background-image:url("/w/images/a/a9/Schloss-Muenster-Philipp-Foelting-CC-BY-SA.jpg"); | | padding: 24px; |
| | display: flex; |
| | align-items: center; |
| | justify-content: center; |
| | overflow: hidden; |
| | border-radius: 12px; |
| | background-color: #2f3e46; /* Fallback-Farbe während das Bild lädt */ |
| | background-image: url("/w/images/a/a9/Schloss-Muenster-Philipp-Foelting-CC-BY-SA.jpg"); |
| background-size: cover; | | background-size: cover; |
| background-position: center; | | background-position: center; |
| min-height:400px; | | background-repeat: no-repeat; |
| } | | } |
|
| |
|
| #chat-messages {
| | /* Dunkles Overlay für bessere Lesbarkeit */ |
| min-height: 120px;
| | .overlay-container::before { |
| max-height: 500px; | | content: ""; |
| overflow-y: auto; | | position: absolute; |
| padding: 8px 0; | | inset: 0; |
| display: flex; | | background: rgba(0, 0, 0, 0.38); |
| flex-direction: column; | | z-index: 1; |
| gap: 12px;
| |
| } | | } |
| #chat-messages:empty::before {
| | |
| content: "Stelle eine Frage und erhalte Antworten basierend auf dem Münster Wiki und ausgewählten Seiten. Beachte: KI-Suche kann Fehler enthalten. Bitte prüfe die Ergebnisse. Personenbezogenen Daten können zur Optimierung der KI-Suche genutzt werden."; | | /* Inhalt über dem Overlay */ |
| display: block; | | .overlay-content { |
| text-align: center; | | position: relative; |
| color: #999; | | z-index: 2; |
| font-size: 14px; | | width: 100%; |
| padding: 40px 16px; | | max-width: 800px; |
| | padding: 20px; |
| | border-radius: 12px; |
| | background: rgba(255, 255, 255, 0.92); |
| | backdrop-filter: blur(4px); |
| | -webkit-backdrop-filter: blur(4px); |
| | box-sizing: border-box; |
| } | | } |
| .chat-msg { | | |
| max-width: 85%; | | /* Falls dein Chat direkt darin liegt */ |
| padding: 10px 14px; | | .overlay-content #chat-widget { |
| border-radius: 10px;
| | max-width: 100%; |
| font-size: 14.5px;
| | margin: 0 auto; |
| line-height: 1.55;
| | background: transparent; |
| word-wrap: break-word;
| | border-radius: 12px; |
| }
| |
| .chat-msg-user {
| |
| align-self: flex-end;
| |
| background: #00308D; | |
| color: #fff;
| |
| border-bottom-right-radius: 3px; | |
| }
| |
| .chat-msg-assistant {
| |
| align-self: flex-start;
| |
| background: #f0f2f5;
| |
| color: #212529; | | color: #212529; |
| border-bottom-left-radius: 3px;
| |
| }
| |
| .chat-msg-assistant p {
| |
| margin: 0 0 8px 0;
| |
| }
| |
| .chat-msg-assistant p:last-child {
| |
| margin-bottom: 0;
| |
| }
| |
| @keyframes chatDots {
| |
| 0%, 80%, 100% { opacity: 0.3; }
| |
| 40% { opacity: 1; }
| |
| } | | } |
| .chat-loading-dots span {
| |
| display: inline-block;
| |
| width: 7px;
| |
| height: 7px;
| |
| margin: 0 2px;
| |
| background: #999;
| |
| border-radius: 50%;
| |
| animation: chatDots 1.2s ease-in-out infinite;
| |
| }
| |
| .chat-loading-dots span:nth-child(2) { animation-delay: 0.15s; }
| |
| .chat-loading-dots span:nth-child(3) { animation-delay: 0.3s; }
| |
| #chat-sources-panel {
| |
| display: none;
| |
| }
| |
| #chat-sources-panel.visible {
| |
| display: block;
| |
| margin: 4px 0 8px 0;
| |
| }
| |
| .chat-sources-toggle {
| |
| background: none;
| |
| border: 1px solid #ddd;
| |
| border-radius: 6px;
| |
| padding: 6px 12px;
| |
| font-size: 12px;
| |
| color: #555;
| |
| cursor: pointer;
| |
| transition: background 0.15s;
| |
| }
| |
| .chat-sources-toggle:hover {
| |
| background: #f5f5f5;
| |
| }
| |
| .chat-sources-list {
| |
| display: none;
| |
| margin-top: 8px;
| |
| }
| |
| .chat-sources-list.open {
| |
| display: block;
| |
| }
| |
| .chat-source-item {
| |
| padding: 10px 12px;
| |
| margin-bottom: 6px;
| |
| border: 1px solid #e0e0e0;
| |
| border-radius: 6px;
| |
| background: #fff;
| |
| transition: border-color 0.15s;
| |
| }
| |
| .chat-source-item:hover {
| |
| border-color: #b0b8c1;
| |
| }
| |
| .chat-source-item h5 {
| |
| margin: 0 0 3px 0;
| |
| font-size: 14px;
| |
| font-weight: 600;
| |
| }
| |
| .chat-source-item h5 a {
| |
| color: #00308D;
| |
| text-decoration: none;
| |
| }
| |
| .chat-source-item h5 a:hover {
| |
| text-decoration: underline;
| |
| }
| |
| .chat-source-item .chat-source-snippet {
| |
| font-size: 12.5px;
| |
| line-height: 1.45;
| |
| color: #666;
| |
| margin: 0;
| |
| }
| |
| .chat-source-item .chat-source-meta {
| |
| font-size: 11px;
| |
| color: #999;
| |
| margin-top: 3px;
| |
| }
| |
| #chat-form {
| |
| display: flex;
| |
| margin-top: 8px;
| |
| }
| |
| #chat-input {
| |
| flex: 1;
| |
| padding: 10px 14px;
| |
| font-size: 15px;
| |
| border: 1px solid #ccc;
| |
| border-right: none;
| |
| border-radius: 4px 0 0 4px;
| |
| outline: none;
| |
| transition: border-color 0.2s;
| |
| color: #212529;
| |
| background: #fff;
| |
| }
| |
| #chat-input:focus {
| |
| border-color: #4CAF50;
| |
| }
| |
| #chat-input:disabled {
| |
| background: #f5f5f5;
| |
| color: #999;
| |
| }
| |
| #chat-send {
| |
| padding: 10px 20px;
| |
| font-size: 15px;
| |
| font-weight: 500;
| |
| cursor: pointer;
| |
| background: #4CAF50;
| |
| color: #fff;
| |
| border: none;
| |
| border-radius: 0 4px 4px 0;
| |
| transition: background 0.2s;
| |
| white-space: nowrap;
| |
| }
| |
| #chat-send:hover {
| |
| background: #43A047;
| |
| }
| |
| #chat-send:disabled {
| |
| background: #a5d6a7;
| |
| cursor: not-allowed;
| |
| }
| |
| #chat-footer {
| |
| display: flex;
| |
| align-items: center;
| |
| justify-content: space-between;
| |
| margin-top: 8px;
| |
| min-height: 28px;
| |
| }
| |
| #chat-status {
| |
| font-size: 12px;
| |
| color: #888;
| |
| }
| |
| #chat-new {
| |
| display: none;
| |
| background: none;
| |
| border: 1px solid #ccc;
| |
| border-radius: 4px;
| |
| padding: 4px 12px;
| |
| font-size: 12px;
| |
| color: #555;
| |
| cursor: pointer;
| |
| transition: background 0.15s;
| |
| }
| |
| #chat-new:hover {
| |
| background: #f5f5f5;
| |
| }
| |
| #chat-new.visible {
| |
| display: inline-block;
| |
| }
| |
| .chat-msg-error {
| |
| align-self: center;
| |
| background: #fef2f2;
| |
| color: #b00;
| |
| border: 1px solid #fca5a5;
| |
| font-size: 13px;
| |
| padding: 8px 14px;
| |
| border-radius: 6px;
| |
| }
| |
| </style>
| |
|
| |
|
| <script>
| | /* Tablet */ |
| (function() { | | @media (max-width: 900px) { |
| var form = document.getElementById('chat-form'); | | .overlay-container { |
| var input = document.getElementById('chat-input');
| | min-height: 340px; |
| var sendBtn = document.getElementById('chat-send');
| | padding: 18px; |
| var messagesEl = document.getElementById('chat-messages');
| | border-radius: 10px; |
| var sourcesPanel = document.getElementById('chat-sources-panel');
| |
| var statusEl = document.getElementById('chat-status');
| |
| var newBtn = document.getElementById('chat-new');
| |
| var apiHost = 'api.' + location.hostname.split('.').slice(1).join('.');
| |
| | |
| var conversationId = null;
| |
| var isLoading = false;
| |
| | |
| function escapeHtml(str) {
| |
| var d = document.createElement('div'); | |
| d.textContent = str; | |
| return d.innerHTML; | |
| } | | } |
|
| |
|
| function truncate(str, len) { | | .overlay-content { |
| if (str.length <= len) return str; | | padding: 16px; |
| return str.substring(0, len).replace(/\s+\S*$/, '') + '\u2026'; | | border-radius: 10px; |
| } | | } |
| | } |
|
| |
|
| function formatAnswer(text) {
| | /* Smartphone */ |
| var html = escapeHtml(text);
| | @media (max-width: 600px) { |
| html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
| | .overlay-container { |
| var paragraphs = html.split(/\n{2,}/);
| | min-height: 280px; |
| if (paragraphs.length > 1) {
| | padding: 12px; |
| html = paragraphs.map(function(p) { return '<p>' + p.replace(/\n/g, '<br>') + '</p>'; }).join('');
| | align-items: stretch; |
| } else { | |
| html = html.replace(/\n/g, '<br>');
| |
| } | |
| return html; | |
| } | | } |
|
| |
|
| function addUserMessage(text) { | | .overlay-content { |
| var div = document.createElement('div');
| | padding: 14px; |
| div.className = 'chat-msg chat-msg-user';
| | border-radius: 8px; |
| div.textContent = text;
| |
| messagesEl.appendChild(div);
| |
| scrollToBottom();
| |
| }
| |
| | |
| function addAssistantMessage(text) {
| |
| var div = document.createElement('div');
| |
| div.className = 'chat-msg chat-msg-assistant';
| |
| div.innerHTML = formatAnswer(text);
| |
| messagesEl.appendChild(div);
| |
| scrollToBottom();
| |
| }
| |
| | |
| function addLoadingIndicator() {
| |
| var div = document.createElement('div'); | |
| div.className = 'chat-msg chat-msg-assistant chat-loading-dots';
| |
| div.id = 'chat-loading'; | |
| div.innerHTML = '<span></span><span></span><span></span>';
| |
| messagesEl.appendChild(div);
| |
| scrollToBottom();
| |
| } | | } |
| | } |
|
| |
|
| function removeLoadingIndicator() {
| | /* Kleine Smartphones */ |
| var el = document.getElementById('chat-loading'); | | @media (max-width: 400px) { |
| if (el) el.remove(); | | .overlay-container { |
| | min-height: 240px; |
| | padding: 10px; |
| } | | } |
|
| |
|
| function addError(msg) { | | .overlay-content { |
| var div = document.createElement('div');
| | padding: 12px; |
| div.className = 'chat-msg chat-msg-error';
| |
| div.textContent = msg;
| |
| messagesEl.appendChild(div);
| |
| scrollToBottom();
| |
| }
| |
| | |
| function scrollToBottom() {
| |
| messagesEl.scrollTop = messagesEl.scrollHeight;
| |
| }
| |
| | |
| function renderSources(sources) {
| |
| if (!sources || sources.length === 0) {
| |
| sourcesPanel.className = '';
| |
| sourcesPanel.innerHTML = '';
| |
| return;
| |
| }
| |
| sourcesPanel.className = 'visible';
| |
| var listId = 'src-list-' + Date.now();
| |
| var html = '<button class="chat-sources-toggle" onclick="var l=document.getElementById(\'' + listId + '\');l.classList.toggle(\'open\');this.textContent=l.classList.contains(\'open\')?\'▲ Quellen verbergen\':\'▼ ' + sources.length + ' Quellen anzeigen\'">'
| |
| + '▼ ' + sources.length + ' Quellen anzeigen</button>';
| |
| html += '<div class="chat-sources-list" id="' + listId + '">';
| |
| sources.forEach(function(s) {
| |
| var pct = Math.round((s.similarity_score || 0) * 100);
| |
| var wikiUrl = '/wiki/' + encodeURIComponent((s.page_title || '').replace(/ /g, '_'));
| |
| html += '<div class="chat-source-item">'
| |
| + '<h5><a href="' + wikiUrl + '">' + escapeHtml(s.page_title || '') + '</a></h5>'
| |
| + '<p class="chat-source-snippet">' + escapeHtml(truncate(s.content_text || '', 150)) + '</p>'
| |
| + '<div class="chat-source-meta">Relevanz: ' + pct + '% · ' + escapeHtml(s.source || '') + '</div>'
| |
| + '</div>';
| |
| });
| |
| html += '</div>';
| |
| sourcesPanel.innerHTML = html;
| |
| }
| |
| | |
| function setLoading(loading) {
| |
| isLoading = loading;
| |
| input.disabled = loading;
| |
| sendBtn.disabled = loading;
| |
| if (loading) {
| |
| addLoadingIndicator();
| |
| } else {
| |
| removeLoadingIndicator();
| |
| }
| |
| }
| |
| | |
| function updateStatus(remaining) {
| |
| if (remaining > 0) {
| |
| statusEl.textContent = remaining + ' R\u00fcckfrage' + (remaining !== 1 ? 'n' : '') + ' verbleibend';
| |
| } else if (remaining === 0) { if (conversationId) {
| |
| statusEl.textContent = 'Keine R\u00fcckfragen mehr m\u00f6glich';
| |
| input.disabled = true;
| |
| sendBtn.disabled = true;
| |
| input.placeholder = 'Starte eine neue Unterhaltung';
| |
| } }
| |
| newBtn.className = conversationId ? 'visible' : '';
| |
| }
| |
| | |
| function resetConversation() {
| |
| conversationId = null;
| |
| messagesEl.innerHTML = '';
| |
| sourcesPanel.className = '';
| |
| sourcesPanel.innerHTML = '';
| |
| statusEl.textContent = '';
| |
| newBtn.className = '';
| |
| input.disabled = false;
| |
| sendBtn.disabled = false;
| |
| input.placeholder = 'Stelle eine Frage \u00fcber M\u00fcnster \u2026';
| |
| input.focus();
| |
| }
| |
| | |
| newBtn.addEventListener('click', resetConversation);
| |
| | |
| form.addEventListener('submit', function(e) {
| |
| e.preventDefault();
| |
| if (isLoading) return;
| |
| var message = input.value.trim();
| |
| if (!message) return;
| |
| | |
| input.value = '';
| |
| addUserMessage(message);
| |
| setLoading(true);
| |
| | |
| var body = { message: message };
| |
| if (conversationId) {
| |
| body.conversation_id = conversationId;
| |
| }
| |
| | |
| var url = location.protocol + '//' + apiHost + '/chat';
| |
| | |
| fetch(url, {
| |
| method: 'POST',
| |
| headers: { 'Content-Type': 'application/json' },
| |
| body: JSON.stringify(body)
| |
| })
| |
| .then(function(res) {
| |
| if (!res.ok) {
| |
| return res.json().then(function(data) {
| |
| throw new Error(data.detail || 'HTTP ' + res.status);
| |
| });
| |
| }
| |
| return res.json();
| |
| })
| |
| .then(function(data) {
| |
| setLoading(false);
| |
| conversationId = data.conversation_id;
| |
| addAssistantMessage(data.answer);
| |
| renderSources(data.sources);
| |
| updateStatus(data.remaining_followups);
| |
| input.focus();
| |
| })
| |
| .catch(function(err) {
| |
| setLoading(false);
| |
| addError('Fehler: ' + err.message);
| |
| input.focus();
| |
| });
| |
| });
| |
| })();
| |
| </script>
| |
| | |
| <style type="text/css">
| |
| | |
| .overlay-container {
| |
| position: relative;
| |
| width: 100%;
| |
| display: inline-block;
| |
| background-image:url("/w/images/a/a9/Schloss-Muenster-Philipp-Foelting-CC-BY-SA.jpg");
| |
| background-size: cover;
| |
| background-position: center;
| |
| min-height:400px;
| |
| }
| |
| | |
| .overlay-content { | |
| position: absolute;
| |
| top: 50%; /* Position des Widgets */
| |
| left: 50%;
| |
| transform: translate(-50%, -50%);
| |
| color: white; /* Textfarbe: Weiß */
| |
| background-color: #00308D; /* Hintergrundfarbe: Blau */
| |
| border-radius: 15px; /* Abgerundete Ecken */
| |
| padding: 20px;
| |
| text-align: center;
| |
| width: 80%; /* Breite des Widgets, kannst du anpassen */
| |
| }
| |
| | |
| .overlay-content p {
| |
| margin: 10px 0; /* Abstand zwischen den Textabsätzen */
| |
| }
| |
| | |
| .overlay-content .headline-text {
| |
| font-size: 1.5em; /* Größerer Schriftzug */
| |
| font-weight: bold; /* Dickere Schrift */
| |
| margin: 10px 0;
| |
| }
| |
| | |
| /* To make images responsive */
| |
| .img-fluid img {
| |
| max-width:100%;
| |
| height:auto;
| |
| }
| |
| | |
| </style>
| |
| | |
| </includeonly>
| |
/* Overlay-Container mit responsive Hintergrundbild */
.overlay-container {
position: relative;
width: 100%;
min-height: 400px;
padding: 24px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
border-radius: 12px;
background-color: #2f3e46; /* Fallback-Farbe während das Bild lädt */
background-image: url("/w/images/a/a9/Schloss-Muenster-Philipp-Foelting-CC-BY-SA.jpg");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
/* Dunkles Overlay für bessere Lesbarkeit */
.overlay-container::before {
content: "";
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.38);
z-index: 1;
}
/* Inhalt über dem Overlay */
.overlay-content {
position: relative;
z-index: 2;
width: 100%;
max-width: 800px;
padding: 20px;
border-radius: 12px;
background: rgba(255, 255, 255, 0.92);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
box-sizing: border-box;
}
/* Falls dein Chat direkt darin liegt */
.overlay-content #chat-widget {
max-width: 100%;
margin: 0 auto;
background: transparent;
border-radius: 12px;
color: #212529;
}
/* Tablet */
@media (max-width: 900px) {
.overlay-container {
min-height: 340px;
padding: 18px;
border-radius: 10px;
}
.overlay-content {
padding: 16px;
border-radius: 10px;
}
}
/* Smartphone */
@media (max-width: 600px) {
.overlay-container {
min-height: 280px;
padding: 12px;
align-items: stretch;
}
.overlay-content {
padding: 14px;
border-radius: 8px;
}
}
/* Kleine Smartphones */
@media (max-width: 400px) {
.overlay-container {
min-height: 240px;
padding: 10px;
}
.overlay-content {
padding: 12px;