Skip to content
Snippets Groups Projects
Commit e25b66f4 authored by Konrad Völkel's avatar Konrad Völkel
Browse files

mostly minor visual changes

parent a252bd53
No related branches found
No related tags found
No related merge requests found
Pipeline #152030 passed
...@@ -10,7 +10,6 @@ const worker = new Worker('./worker.js', { type: 'module' }); ...@@ -10,7 +10,6 @@ const worker = new Worker('./worker.js', { type: 'module' });
/** get the up to date FAQ from site */ /** get the up to date FAQ from site */
const textData = await extractFAQfromHTML("FAQ.html"); const textData = await extractFAQfromHTML("FAQ.html");
/** import precompiled embeddings and check for missing entries */ /** import precompiled embeddings and check for missing entries */
console.time("loadLargeEmbeddings"); console.time("loadLargeEmbeddings");
let embeddingStack = await loadEmbedding('largeEmbedding', './embeddings/largeEmbedding.json'); let embeddingStack = await loadEmbedding('largeEmbedding', './embeddings/largeEmbedding.json');
...@@ -33,54 +32,41 @@ localStorage.setItem('largeEmbedding', JSON.stringify(embeddingStack)); ...@@ -33,54 +32,41 @@ localStorage.setItem('largeEmbedding', JSON.stringify(embeddingStack));
localStorage.setItem('smallEmbedding', JSON.stringify(tokenEmbeddingStack)); localStorage.setItem('smallEmbedding', JSON.stringify(tokenEmbeddingStack));
/** handeling results iframe */
const inputElement = document.getElementById('user-input'); const inputElement = document.getElementById('user-input');
const resultsIframe = parent.document.getElementById('resultsIframe'); const resultsContainer = document.getElementById('results');
let topResult = null; let topResult = null;
inputElement.addEventListener('input', function (event) { inputElement.addEventListener('input', function (event) {
const query = event.target.value.trim(); const query = event.target.value.trim();
const results = resultsIframe.contentDocument || resultsIframe.contentWindow.document;
const resultsContainer = results.getElementById('results');
/** hide results when no query is typed */ /** hide results when no query is typed */
if (!query) { if (!query) {
resultsContainer.innerHTML = ''; resultsContainer.innerHTML = '';
setTimeout(() => { resultsContainer.style.display = 'none';
resultsIframe.style.display = 'none';
}, 500);
return; return;
} }
resultsIframe.style.display = 'block'; resultsContainer.style.display = 'block';
resultsContainer.innerHTML = ''; resultsContainer.innerHTML = '';
processQuery(query, worker, function (outputs) { processQuery(query, worker, function (outputs) {
window.focus(); window.focus();
outputs.forEach(async output => { outputs.forEach(async output => {
const resultLink = results.createElement('a'); /** display live results */
resultLink.href = 'javascript:void(0);'; const resultLink = document.createElement('div');
resultLink.className = 'result'; resultLink.className = 'result';
resultLink.style.display = 'block';
/** display question text in result iframe */ /** display question text */
const questionDiv = results.createElement('div'); const questionDiv = document.createElement('div');
questionDiv.className = 'result-question'; questionDiv.className = 'result-question';
questionDiv.innerHTML = `<strong>${output.question}</strong>`; questionDiv.innerHTML = `<strong>${output.question}</strong>`;
resultLink.appendChild(questionDiv); resultLink.appendChild(questionDiv);
/** display our most relevant token to question in result iframe */ /** display our most relevant token to question */
const bestTokenDiv = results.createElement('div'); const bestTokenDiv = document.createElement('div');
bestTokenDiv.className = 'result-token'; bestTokenDiv.className = 'result-token';
let tokenText = output.bestToken; let tokenText = output.bestToken;
/** shorten our best token; only 100 chars displayed*/
if (tokenText.length > 100) { if (tokenText.length > 100) {
tokenText = tokenText.substring(0, 100); tokenText = tokenText.substring(0, 100);
} }
...@@ -100,9 +86,9 @@ inputElement.addEventListener('input', function (event) { ...@@ -100,9 +86,9 @@ inputElement.addEventListener('input', function (event) {
if (outputs.length > 0) { if (outputs.length > 0) {
topResult = outputs[0]; topResult = outputs[0];
} }
}); });
}); });
/** search for query on enter press and put it in chat */ /** search for query on enter press and put it in chat */
document.getElementById('user-input').addEventListener('keypress', function (event) { document.getElementById('user-input').addEventListener('keypress', function (event) {
if (event.key === 'Enter') { if (event.key === 'Enter') {
...@@ -113,10 +99,8 @@ document.getElementById('user-input').addEventListener('keypress', function (eve ...@@ -113,10 +99,8 @@ document.getElementById('user-input').addEventListener('keypress', function (eve
} }
}); });
export function linkAndClick(output) { export function linkAndClick(output) {
saveMessage(); saveMessage();
setTimeout(() => { setTimeout(() => {
const encodedQuestion = encodeURIComponent(output); const encodedQuestion = encodeURIComponent(output);
const panels = document.querySelectorAll( const panels = document.querySelectorAll(
......
...@@ -24,7 +24,6 @@ export function appendMessage(content, className, linkId = null, akkordeonId = n ...@@ -24,7 +24,6 @@ export function appendMessage(content, className, linkId = null, akkordeonId = n
const panelDiv = document.createElement('div'); const panelDiv = document.createElement('div');
panelDiv.innerHTML = '<i class="fa-solid fa-down-long"></i>'; panelDiv.innerHTML = '<i class="fa-solid fa-down-long"></i>';
panelDiv.className = 'info-panel'; panelDiv.className = 'info-panel';
panelDiv.setAttribute('data-question', encodeURIComponent(content)); panelDiv.setAttribute('data-question', encodeURIComponent(content));
messageDiv.onclick = function(event) { messageDiv.onclick = function(event) {
...@@ -33,15 +32,12 @@ export function appendMessage(content, className, linkId = null, akkordeonId = n ...@@ -33,15 +32,12 @@ export function appendMessage(content, className, linkId = null, akkordeonId = n
} }
panelDiv.onclick = function (event) { panelDiv.onclick = function (event) {
event.stopPropagation(); event.stopPropagation();
let nextElem = messageContainer.nextElementSibling; let nextElem = messageContainer.nextElementSibling;
if (nextElem && nextElem.classList.contains('answer-container')) { if (nextElem && nextElem.classList.contains('answer-container')) {
nextElem.remove(); nextElem.remove();
panelDiv.innerHTML = '<i class="fa-solid fa-down-long"></i>'; panelDiv.innerHTML = '<i class="fa-solid fa-down-long"></i>';
panelDiv.classList.remove('active'); panelDiv.classList.remove('active');
return; return;
} }
panelDiv.innerHTML = '<i class="fa-solid fa-up-long"></i>'; panelDiv.innerHTML = '<i class="fa-solid fa-up-long"></i>';
...@@ -50,19 +46,15 @@ export function appendMessage(content, className, linkId = null, akkordeonId = n ...@@ -50,19 +46,15 @@ export function appendMessage(content, className, linkId = null, akkordeonId = n
const answerContainer = document.createElement('div'); const answerContainer = document.createElement('div');
answerContainer.className = 'answer-container'; answerContainer.className = 'answer-container';
answerContainer.innerHTML = highlightToken; answerContainer.innerHTML = highlightToken;
messageContainer.parentNode.insertBefore(answerContainer, messageContainer.nextSibling); messageContainer.parentNode.insertBefore(answerContainer, messageContainer.nextSibling);
panelDiv.classList.add('active'); panelDiv.classList.add('active');
} }
messageContainer.appendChild(numberBox); messageContainer.appendChild(numberBox);
messageContainer.appendChild(messageDiv); messageContainer.appendChild(messageDiv);
messageContainer.appendChild(panelDiv); messageContainer.appendChild(panelDiv);
} }
const messagesDiv = document.getElementById('messages'); const messagesDiv = document.getElementById('messages');
...@@ -72,29 +64,23 @@ export function appendMessage(content, className, linkId = null, akkordeonId = n ...@@ -72,29 +64,23 @@ export function appendMessage(content, className, linkId = null, akkordeonId = n
/** gets query from input field and performs search */ /** gets query from input field and performs search */
export function sendMessage(worker) { export function sendMessage(worker) {
const userInput = document.getElementById('user-input'); const userInput = document.getElementById('user-input');
const message = userInput.value.trim(); const message = userInput.value.trim();
const resultsIframe = parent.document.getElementById('resultsIframe');
const results = resultsIframe.contentDocument || resultsIframe.contentWindow.document; const resultsContainer = document.getElementById('results');
const resultsContainer = results.getElementById('results');
/** hide results when message is sent */ /** hide results when message is sent */
resultsContainer.innerHTML = ''; resultsContainer.innerHTML = '';
setTimeout(() => { setTimeout(() => {
resultsIframe.style.display = 'none'; resultsContainer.style.display = 'none';
}, 500); }, 500);
resultsIframe.style.display = 'block'; resultsContainer.style.display = 'block';
resultsContainer.innerHTML = ''; resultsContainer.innerHTML = '';
if (message !== "") { if (message !== "") {
appendMessage(message, 'user-message'); appendMessage(message, 'user-message');
userInput.value = ''; userInput.value = '';
worker.postMessage({ worker.postMessage({
act: 'semanticSearch', act: 'semanticSearch',
...@@ -103,29 +89,23 @@ export function sendMessage(worker) { ...@@ -103,29 +89,23 @@ export function sendMessage(worker) {
} }
} }
/** new feedback buttons with font-awesome style */ /** new feedback buttons with font-awesome style */
export function drawFeedbackButtons(query, bestTokens) { export function drawFeedbackButtons(query, bestTokens) {
const messagesDiv = document.getElementById('messages'); const messagesDiv = document.getElementById('messages');
const feedbackContainer = document.createElement('div'); const feedbackContainer = document.createElement('div');
feedbackContainer.className = 'feedback-container'; feedbackContainer.className = 'feedback-container';
const plusButton = document.createElement('button'); const plusButton = document.createElement('button');
plusButton.innerHTML = '<i class="fa-solid fa-thumbs-up"></i>'; plusButton.innerHTML = '<i class="fa-solid fa-thumbs-up"></i>';
plusButton.className = 'feedback-button thumbs-up'; plusButton.className = 'feedback-button thumbs-up';
plusButton.onclick = function () { plusButton.onclick = function () {
submitFeedback(query, bestTokens, 'good'); submitFeedback(query, bestTokens, 'good');
}; };
const minusButton = document.createElement('button'); const minusButton = document.createElement('button');
minusButton.innerHTML = '<i class="fa-solid fa-thumbs-down"></i>'; minusButton.innerHTML = '<i class="fa-solid fa-thumbs-down"></i>';
minusButton.className = 'feedback-button thumbs-down'; minusButton.className = 'feedback-button thumbs-down';
minusButton.onclick = function () { minusButton.onclick = function () {
submitFeedback(query, bestTokens, 'bad'); submitFeedback(query, bestTokens, 'bad');
}; };
...@@ -134,18 +114,16 @@ export function drawFeedbackButtons(query, bestTokens) { ...@@ -134,18 +114,16 @@ export function drawFeedbackButtons(query, bestTokens) {
messagesDiv.appendChild(feedbackContainer); messagesDiv.appendChild(feedbackContainer);
} }
/** Intro panel for chat resonses*/ /** Intro panel for chat responses */
export function drawUserInfo() { export function drawUserInfo() {
const messagesDiv = document.getElementById('messages'); const messagesDiv = document.getElementById('messages');
const infoDiv = document.createElement('div'); const infoDiv = document.createElement('div');
infoDiv.className = 'bot-intro'; infoDiv.className = 'bot-intro';
infoDiv.innerHTML = "This might be useful:<br>"; infoDiv.innerHTML = "This might be useful:<br>";
messagesDiv.appendChild(infoDiv); messagesDiv.appendChild(infoDiv);
} }
/** new message to inform user of the limited usability; out for now*/ /** new message to inform user of the limited usability; out for now*/
export function discloseLimitations() { export function discloseLimitations() {
......
...@@ -52,7 +52,7 @@ export function handleWorker(events){ ...@@ -52,7 +52,7 @@ export function handleWorker(events){
break; break;
case 'topResults': case 'topResults':
/** show results live in result iframe */ /** show results live in result */
if (processQueryCache) { if (processQueryCache) {
const outputs = results.slice(0, 3).map(result => ({ const outputs = results.slice(0, 3).map(result => ({
question: result.question, question: result.question,
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>HHU Search Helper</title> <title>HHU Search Helper - Combined</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
<style> <style>
body { body {
overflow: hidden; overflow: hidden;
...@@ -11,38 +13,21 @@ ...@@ -11,38 +13,21 @@
</head> </head>
<body> <body>
<iframe id="chatIframe" src="chatbox.html" style="position: relative; width: 100%; border: none;" title="HHU Search Helper"></iframe> <div id="chatbox">
<iframe id="resultsIframe" src="results.html" style="position: sticky; left: 15px; min-height: 300px; transition: opacity 1s ease-in-out, transform 1s ease-in-out; background-color: #f0f0f0; width: 95%; overflow: hidden; padding: 10px; border-radius: 5px; border: none; display: none; overflow: hidden;"></iframe> <div id="chatbox-title">Ask hAInrich</div>
<div id="messages"></div>
<div id="messageInfo"></div>
<div id="input-container">
<input type="text" id="user-input" placeholder="Try asking: 'minimum admission grade' or 'I'm from outside the EU'">
<button onclick="sendAsk()">Ask</button>
<script>
/** make iframes grow with iframes inside it */
function adjustIframeSize() { </div>
<div id="results"></div>
const chatIframe = document.getElementById('chatIframe'); </div>
const resultsIframe = document.getElementById('resultsIframe');
let totalHeight = 0; <script type="module" src="index.js" async></script>
if (chatIframe.offsetHeight) {
totalHeight += chatIframe.offsetHeight;
}
if (resultsIframe.style.display !== 'none' && resultsIframe.offsetHeight) {
totalHeight += resultsIframe.offsetHeight;
}
if (window.frameElement) {
window.frameElement.style.height = totalHeight + 'px';
}
}
document.getElementById('chatIframe').addEventListener('load', adjustIframeSize);
document.getElementById('resultsIframe').addEventListener('load', adjustIframeSize);
const observer = new MutationObserver(adjustIframeSize);
observer.observe(document.body, { childList: true, subtree: true, attributes: true });
</script>
</body> </body>
</html> </html>
...@@ -2,20 +2,16 @@ ...@@ -2,20 +2,16 @@
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
} }
#chatbox { #chatbox {
background-color: #d3d3d3;
position: sticky; position: sticky;
width: 100%; max-height: 900px;
max-height: 400px; overflow: hidden;
overflow-x: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow-y: hidden;
} }
#chatbox-title { #chatbox-title {
position: relative;
background-color: #003865; background-color: #003865;
color: white; color: white;
text-align: center; text-align: center;
...@@ -28,11 +24,12 @@ ...@@ -28,11 +24,12 @@
} }
#messages { #messages {
background-color: #d3d3d3;
flex: 1; flex: 1;
left: 10px; left: 10px;
padding: 10px; padding: 10px;
display: flex; display: flex;
max-height: 270px; max-height: 300px;
flex-direction: column; flex-direction: column;
overflow-x: hidden; overflow-x: hidden;
z-index: -3; z-index: -3;
...@@ -45,6 +42,7 @@ ...@@ -45,6 +42,7 @@
} }
#input-container { #input-container {
background-color: #d3d3d3;
display: flex; display: flex;
padding: 10px; padding: 10px;
height: 50px; height: 50px;
...@@ -72,7 +70,6 @@ ...@@ -72,7 +70,6 @@
background-color: #0056b3; background-color: #0056b3;
} }
.user-message { .user-message {
align-self: flex-end; align-self: flex-end;
background-color: #007bff; background-color: #007bff;
...@@ -85,8 +82,6 @@ ...@@ -85,8 +82,6 @@
text-align: center; text-align: center;
} }
.answer-container { .answer-container {
white-space: pre-wrap; white-space: pre-wrap;
align-self: flex-start; align-self: flex-start;
...@@ -99,27 +94,13 @@ ...@@ -99,27 +94,13 @@
cursor: default; cursor: default;
opacity: 0; opacity: 0;
animation: showUp 0.3s forwards; animation: showUp 0.3s forwards;
} }
.highlight { .highlight {
background-color: rgb(59, 136, 172); background-color: rgb(59, 136, 172);
color: white; /* Adjust as needed for contrast */ color: white;
}
@keyframes showUp {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
} }
.info-for-user { .info-for-user {
position: relative; position: relative;
margin-right: auto; margin-right: auto;
...@@ -128,7 +109,6 @@ ...@@ -128,7 +109,6 @@
background-color: rgb(0, 0, 0, 0.8); background-color: rgb(0, 0, 0, 0.8);
color: white; color: white;
flex-direction: row; flex-direction: row;
max-width: 150px;
text-align: left; text-align: left;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
...@@ -140,7 +120,6 @@ ...@@ -140,7 +120,6 @@
max-width: 50%; max-width: 50%;
vertical-align: top; vertical-align: top;
margin-right: 20px; margin-right: 20px;
} }
.bot-message { .bot-message {
...@@ -154,7 +133,6 @@ ...@@ -154,7 +133,6 @@
text-align: middle; text-align: middle;
z-index: 100; z-index: 100;
cursor: pointer; cursor: pointer;
} }
.bot-intro { .bot-intro {
...@@ -166,15 +144,11 @@ ...@@ -166,15 +144,11 @@
max-width: 60%; max-width: 60%;
word-wrap: break-word; word-wrap: break-word;
text-align: middle; text-align: middle;
} }
.bot-message-container { .bot-message-container {
display: flex; display: flex;
align-items: stretch; align-items: stretch;
} }
.bot-message:hover { .bot-message:hover {
...@@ -185,7 +159,6 @@ ...@@ -185,7 +159,6 @@
transform: scale(1.03); transform: scale(1.03);
} }
.info-panel { .info-panel {
background-color: #0056b3; background-color: #0056b3;
color: rgb(255, 255, 255); color: rgb(255, 255, 255);
...@@ -249,7 +222,6 @@ ...@@ -249,7 +222,6 @@
.feedback-container { .feedback-container {
position: relative; position: relative;
margin-left: auto; margin-left: auto;
left: -20px; left: -20px;
color: #000; color: #000;
cursor: pointer; cursor: pointer;
...@@ -257,7 +229,6 @@ ...@@ -257,7 +229,6 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 0px;
padding: 3px; padding: 3px;
font-size: 12px; font-size: 12px;
border-radius: 4px; border-radius: 4px;
...@@ -284,7 +255,6 @@ ...@@ -284,7 +255,6 @@
.feedback-container:hover::after { .feedback-container:hover::after {
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
} }
.feedback-button { .feedback-button {
...@@ -307,59 +277,61 @@ ...@@ -307,59 +277,61 @@
} }
#results { #results {
position: sticky; display: none;
position: relative;
background-color: #f0f0f0; background-color: #f0f0f0;
width: auto;
z-index: 1000;
margin: 20px;
padding: 10px; padding: 10px;
width: 95%; min-height: 200px;
display: block;
max-height: auto;
overflow: hidden; overflow: hidden;
border-radius: 5px;
flex-grow: 1;
animation: showUp 0.3s forwards;
} }
#results .show { #results .show {
position: relative;
display: block;
opacity: 1; opacity: 1;
transform: translateY(0); width: 100%;
visibility: visible; visibility: visible;
overflow: hidden; padding: 5px;
min-height: 200px;
} }
#results .result { #results .result {
padding: 4px 8px; position: relative;
margin-bottom: 4px; margin-bottom: 4px;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
font-size: 17px; font-size: 17px;
padding-left: 5%; padding: 5px;
padding-right: 10%; margin: 10px;
overflow: hidden;
text-decoration: none; text-decoration: none;
color: inherit; color: inherit;
} }
#results .result:hover { #results .result:hover {
position: relative;
cursor: pointer;
background-color: #e0e0e0; background-color: #e0e0e0;
overflow: hidden; overflow: hidden;
padding: 5px;
font-size: 18px; font-size: 18px;
border-radius: 5px;
} }
.confirm { @keyframes showUp {
position: fixed; from {
top: 60px;
right: 20px;
background-color: #50bd54;
color: #fff;
padding: 10px 15px;
border-radius: 5px;
opacity: 0; opacity: 0;
transition: opacity 0.5s ease-in-out; transform: translateY(-10px);
pointer-events: none;
z-index: 5;
} }
to {
.confirm.visible {
opacity: 1; opacity: 1;
transform: translateY(0);
} }
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment