Widget:StartseitenSuche: Unterschied zwischen den Versionen
Aus MediaWiki
KKeine Bearbeitungszusammenfassung |
KKeine Bearbeitungszusammenfassung |
||
| Zeile 1: | Zeile 1: | ||
<includeonly> | <includeonly> | ||
<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 mir deine Frage …" 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> | ||
</div> | </div> | ||
| Zeile 58: | Zeile 54: | ||
#chat-widget { | #chat-widget { | ||
width: | max-width: 800px; | ||
margin: 0 auto; | margin: 0 auto; | ||
font-family: -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; | font-family: -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; | ||
| Zeile 64: | Zeile 60: | ||
display: flex; | display: flex; | ||
flex-direction: column; | flex-direction: column; | ||
} | } | ||
#chat-messages { | #chat-messages { | ||
min-height: 120px; | min-height: 120px; | ||
| Zeile 76: | Zeile 70: | ||
gap: 12px; | gap: 12px; | ||
} | } | ||
#chat-messages:empty::before { | #chat-messages:empty::before { | ||
content: "Stelle eine Frage und erhalte Antworten basierend auf dem Münster Wiki und ausgewählten Web-Inhalten für Münster. Beachte: KI-Suche kann Fehler machen. Prüfe deine Ergebnisse sorgfältig. Verwende keine personenbezogenen Daten."; | content: "Stelle eine Frage und erhalte Antworten basierend auf dem Münster Wiki und ausgewählten Web-Inhalten für Münster. Beachte: KI-Suche kann Fehler machen. Prüfe deine Ergebnisse sorgfältig. Verwende keine personenbezogenen Daten."; | ||
display: block; | display: block; | ||
text-align: center; | text-align: center; | ||
color: # | color: #999; | ||
font-size: 14px; | font-size: 14px; | ||
padding: | padding: 40px 16px; | ||
} | } | ||
.chat-msg { | .chat-msg { | ||
max-width: 85%; | max-width: 85%; | ||
| Zeile 94: | Zeile 86: | ||
word-wrap: break-word; | word-wrap: break-word; | ||
} | } | ||
.chat-msg-user { | .chat-msg-user { | ||
align-self: flex-end; | align-self: flex-end; | ||
| Zeile 101: | Zeile 92: | ||
border-bottom-right-radius: 3px; | border-bottom-right-radius: 3px; | ||
} | } | ||
.chat-msg-assistant { | .chat-msg-assistant { | ||
align-self: flex-start; | align-self: flex-start; | ||
| Zeile 108: | Zeile 98: | ||
border-bottom-left-radius: 3px; | border-bottom-left-radius: 3px; | ||
} | } | ||
.chat-msg-assistant p { | .chat-msg-assistant p { | ||
margin: 0 0 8px 0; | margin: 0 0 8px 0; | ||
} | } | ||
.chat-msg-assistant p:last-child { | .chat-msg-assistant p:last-child { | ||
margin-bottom: 0; | margin-bottom: 0; | ||
} | } | ||
@keyframes chatDots { | @keyframes chatDots { | ||
0%, 80%, 100% { opacity: 0.3; } | 0%, 80%, 100% { opacity: 0.3; } | ||
40% { opacity: 1; } | 40% { opacity: 1; } | ||
} | } | ||
.chat-loading-dots span { | .chat-loading-dots span { | ||
display: inline-block; | display: inline-block; | ||
| Zeile 131: | Zeile 117: | ||
animation: chatDots 1.2s ease-in-out infinite; | 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(2) { animation-delay: 0.15s; } | ||
.chat-loading-dots span:nth-child(3) { animation-delay: 0.3s; } | .chat-loading-dots span:nth-child(3) { animation-delay: 0.3s; } | ||
#chat-sources-panel { | #chat-sources-panel { | ||
display: none; | display: none; | ||
} | } | ||
#chat-sources-panel.visible { | #chat-sources-panel.visible { | ||
display: block; | display: block; | ||
margin: 4px 0 8px 0; | margin: 4px 0 8px 0; | ||
} | } | ||
.chat-sources-toggle { | .chat-sources-toggle { | ||
background: none; | background: none; | ||
| Zeile 154: | Zeile 136: | ||
transition: background 0.15s; | transition: background 0.15s; | ||
} | } | ||
.chat-sources-toggle:hover { | .chat-sources-toggle:hover { | ||
background: #f5f5f5; | background: #f5f5f5; | ||
} | } | ||
.chat-sources-list { | .chat-sources-list { | ||
display: none; | display: none; | ||
margin-top: 8px; | margin-top: 8px; | ||
} | } | ||
.chat-sources-list.open { | .chat-sources-list.open { | ||
display: block; | display: block; | ||
} | } | ||
.chat-source-item { | .chat-source-item { | ||
padding: 10px 12px; | padding: 10px 12px; | ||
| Zeile 176: | Zeile 154: | ||
transition: border-color 0.15s; | transition: border-color 0.15s; | ||
} | } | ||
.chat-source-item:hover { | .chat-source-item:hover { | ||
border-color: #b0b8c1; | border-color: #b0b8c1; | ||
} | } | ||
.chat-source-item h5 { | .chat-source-item h5 { | ||
margin: 0 0 3px 0; | margin: 0 0 3px 0; | ||
| Zeile 186: | Zeile 162: | ||
font-weight: 600; | font-weight: 600; | ||
} | } | ||
.chat-source-item h5 a { | .chat-source-item h5 a { | ||
color: #00308D; | color: #00308D; | ||
text-decoration: none; | text-decoration: none; | ||
} | } | ||
.chat-source-item h5 a:hover { | .chat-source-item h5 a:hover { | ||
text-decoration: underline; | text-decoration: underline; | ||
} | } | ||
.chat-source-item .chat-source-snippet { | .chat-source-item .chat-source-snippet { | ||
font-size: 12.5px; | font-size: 12.5px; | ||
| Zeile 202: | Zeile 175: | ||
margin: 0; | margin: 0; | ||
} | } | ||
.chat-source-item .chat-source-meta { | .chat-source-item .chat-source-meta { | ||
font-size: 11px; | font-size: 11px; | ||
| Zeile 208: | Zeile 180: | ||
margin-top: 3px; | margin-top: 3px; | ||
} | } | ||
#chat-form { | #chat-form { | ||
display: flex; | display: flex; | ||
margin-top: 8px; | margin-top: 8px; | ||
} | } | ||
#chat-input { | #chat-input { | ||
flex: 1; | flex: 1; | ||
| Zeile 225: | Zeile 195: | ||
color: #212529; | color: #212529; | ||
background: #fff; | background: #fff; | ||
} | } | ||
#chat-input:focus { | #chat-input:focus { | ||
border-color: #4CAF50; | border-color: #4CAF50; | ||
} | } | ||
#chat-input:disabled { | #chat-input:disabled { | ||
background: #f5f5f5; | background: #f5f5f5; | ||
color: #999; | color: #999; | ||
} | } | ||
#chat-send { | #chat-send { | ||
padding: 10px 20px; | padding: 10px 20px; | ||
| Zeile 249: | Zeile 215: | ||
white-space: nowrap; | white-space: nowrap; | ||
} | } | ||
#chat-send:hover { | #chat-send:hover { | ||
background: #43A047; | background: #43A047; | ||
} | } | ||
#chat-send:disabled { | #chat-send:disabled { | ||
background: #a5d6a7; | background: #a5d6a7; | ||
cursor: not-allowed; | cursor: not-allowed; | ||
} | } | ||
#chat-footer { | #chat-footer { | ||
display: flex; | display: flex; | ||
align-items: center; | align-items: center; | ||
justify-content: space-between; | justify-content: space-between; | ||
margin-top: 8px; | margin-top: 8px; | ||
min-height: 28px; | min-height: 28px; | ||
} | } | ||
#chat-status { | #chat-status { | ||
font-size: 12px; | font-size: 12px; | ||
color: # | color: #888; | ||
} | } | ||
#chat-new { | #chat-new { | ||
display: none; | display: none; | ||
| Zeile 284: | Zeile 244: | ||
transition: background 0.15s; | transition: background 0.15s; | ||
} | } | ||
#chat-new:hover { | #chat-new:hover { | ||
background: #f5f5f5; | background: #f5f5f5; | ||
} | } | ||
#chat-new.visible { | #chat-new.visible { | ||
display: inline-block; | display: inline-block; | ||
} | } | ||
.chat-msg-error { | .chat-msg-error { | ||
align-self: center; | align-self: center; | ||
| Zeile 301: | Zeile 258: | ||
padding: 8px 14px; | padding: 8px 14px; | ||
border-radius: 6px; | border-radius: 6px; | ||
} | } | ||
</style> | </style> | ||
| Zeile 400: | Zeile 283: | ||
function truncate(str, len) { | function truncate(str, len) { | ||
if (str.length <= len) return str; | if (str.length <= len) return str; | ||
return str.substring(0, len).replace(/ | return str.substring(0, len).replace(/\s+\S*$/, '') + '\u2026'; | ||
} | } | ||
function formatAnswer(text) { | function formatAnswer(text) { | ||
var html = escapeHtml(text); | var html = escapeHtml(text); | ||
html = html.replace(/ | html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>'); | ||
var paragraphs = html.split(/ | var paragraphs = html.split(/\n{2,}/); | ||
if (paragraphs.length > 1) { | if (paragraphs.length > 1) { | ||
html = paragraphs.map(function(p) { return '<p>' + p.replace(/ | html = paragraphs.map(function(p) { return '<p>' + p.replace(/\n/g, '<br>') + '</p>'; }).join(''); | ||
} else { | } else { | ||
html = html.replace(/ | html = html.replace(/\n/g, '<br>'); | ||
} | } | ||
return html; | return html; | ||
| Zeile 465: | Zeile 348: | ||
sourcesPanel.className = 'visible'; | sourcesPanel.className = 'visible'; | ||
var listId = 'src-list-' + Date.now(); | var listId = 'src-list-' + Date.now(); | ||
var html = '<button class="chat-sources-toggle" onclick="var l=document.getElementById( | 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>'; | + '▼ ' + sources.length + ' Quellen anzeigen</button>'; | ||
html += '<div class="chat-sources-list" id="' + listId + '">'; | html += '<div class="chat-sources-list" id="' + listId + '">'; | ||
sources.forEach(function(s) { | sources.forEach(function(s) { | ||
var pct = Math.round((s. | var pct = Math.round((s.score || 0) * 100); | ||
var | var url = s.url || ''; | ||
var title = ''; | |||
if (url) { | |||
var seg = url.split('/').pop(); | |||
try { seg = decodeURIComponent(seg); } catch (e) {} | |||
title = seg.replace(/_/g, ' '); | |||
} | |||
html += '<div class="chat-source-item">' | html += '<div class="chat-source-item">' | ||
+ '<h5><a href="' + | + '<h5><a href="' + escapeHtml(url) + '">' + escapeHtml(title) + '</a></h5>' | ||
+ '<p class="chat-source-snippet">' + escapeHtml(truncate(s. | + '<p class="chat-source-snippet">' + escapeHtml(truncate(s.content || '', 150)) + '</p>' | ||
+ '<div class="chat-source-meta">Relevanz: ' + pct + '% · ' + escapeHtml(s.source || '') + '</div>' | + '<div class="chat-source-meta">Relevanz: ' + pct + '% · ' + escapeHtml(s.source || '') + '</div>' | ||
+ '</div>'; | + '</div>'; | ||
| Zeile 494: | Zeile 383: | ||
function updateStatus(remaining) { | function updateStatus(remaining) { | ||
if (remaining > 0) { | if (remaining > 0) { | ||
statusEl.textContent = remaining + ' R | statusEl.textContent = remaining + ' R\u00fcckfrage' + (remaining !== 1 ? 'n' : '') + ' verbleibend'; | ||
} else if (remaining === 0) { | } 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' : ''; | newBtn.className = conversationId ? 'visible' : ''; | ||
} | } | ||
| Zeile 515: | Zeile 402: | ||
input.disabled = false; | input.disabled = false; | ||
sendBtn.disabled = false; | sendBtn.disabled = false; | ||
input.placeholder = 'Stelle eine Frage | input.placeholder = 'Stelle eine Frage \u00fcber M\u00fcnster \u2026'; | ||
input.focus(); | input.focus(); | ||
} | } | ||