286 lines
11 KiB
HTML
286 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html data-theme="dark" lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
|
<title>JADE</title>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
|
|
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet">
|
|
|
|
<!--link rel="stylesheet" href="/animations.css"-->
|
|
<link rel="stylesheet" href="/style.css">
|
|
|
|
<script src="https://unpkg.com/htmx.org@2.0.0-beta4/dist/htmx.js"></script>
|
|
<script src="https://unpkg.com/htmx-ext-sse@2.0.0/sse.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>
|
|
|
|
<script async src="https://js.stripe.com/v3/pricing-table.js"></script>
|
|
|
|
<!-- highlight.js -->
|
|
<link rel="stylesheet" href="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/styles/default.min.css">
|
|
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/highlight.min.js"></script>
|
|
<script>hljs.highlightAll();</script>
|
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
|
|
<script src="wasm_exec.js"></script>
|
|
<script>
|
|
const go = new Go();
|
|
WebAssembly.instantiateStreaming(fetch("main-v1.wasm"), go.importObject).then((result) => {
|
|
go.run(result.instance);
|
|
});
|
|
</script>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
{{ embed }}
|
|
|
|
<script>
|
|
// run printHello(); every 5 seconds
|
|
setInterval(function () {
|
|
printHello();
|
|
}, 5000);
|
|
|
|
function generateMessagePlaceholder(content) {
|
|
marked.setOptions({
|
|
highlight: function (code, lang) {
|
|
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
|
|
return hljs.highlight(code, { language }).value;
|
|
}
|
|
});
|
|
|
|
// Convert the markdown content to HTML
|
|
const htmlContent = marked(content);
|
|
|
|
let userString = `
|
|
<div class="message-user mt-3 message-placeholder">
|
|
<div class="columns is-mobile">
|
|
<div class="column is-narrow" id="icon-column">
|
|
<figure class="image is-48x48 message-icon" style="flex-shrink: 0;">
|
|
<img src="icons/bouvai2.png" alt="User Image">
|
|
</figure>
|
|
</div>
|
|
|
|
<div class="column" id="content-column" style="width: 100px;">
|
|
<div class="is-flex is-align-items-start">
|
|
<div class="message-content" style="width: 100%; overflow-y: hidden;">
|
|
<div class="message-header">
|
|
<p>
|
|
You
|
|
</p>
|
|
</div>
|
|
<div class="message-body">
|
|
<div class="content" style="overflow-x: auto; width: 100%;">
|
|
${htmlContent}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="is-flex is-justify-content mt-2">
|
|
<div style="height: 30px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
let botString = `
|
|
<div class="message-bot mt-3 message-placeholder">
|
|
<div class="columns is-mobile">
|
|
<div class="column is-narrow" id="icon-column">
|
|
<figure class="image is-48x48 message-icon" style="flex-shrink: 0;">
|
|
<img src="icons/bouvai2.png" alt="User Image">
|
|
</figure>
|
|
</div>
|
|
|
|
<div class="column" style="width: 100px;">
|
|
<div class="is-flex is-align-items-start">
|
|
<div class="message-content">
|
|
<div class='message-header'>
|
|
<p>
|
|
Waiting...
|
|
</p>
|
|
</div>
|
|
<div class="message-body">
|
|
<div class="content">
|
|
<br>
|
|
<img src="/puff.svg" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
return userString + botString;
|
|
}
|
|
</script>
|
|
|
|
|
|
<script>
|
|
function copyToClipboardCode(button) {
|
|
// Get the code element next to the button
|
|
var codeElement = button.parentElement.nextElementSibling;
|
|
|
|
// Create a temporary textarea element
|
|
var tempTextarea = document.createElement('textarea');
|
|
tempTextarea.value = codeElement.textContent;
|
|
|
|
// Append the temporary textarea to the document body
|
|
document.body.appendChild(tempTextarea);
|
|
|
|
// Select the text in the temporary textarea
|
|
tempTextarea.select();
|
|
|
|
// Copy the selected text to the clipboard
|
|
document.execCommand('copy');
|
|
|
|
// Remove the temporary textarea from the document body
|
|
document.body.removeChild(tempTextarea);
|
|
|
|
// Change the button text to indicate successful copy
|
|
var originalText = button.innerHTML;
|
|
button.innerHTML = '<i class="fa-solid fa-check"></i>';
|
|
|
|
// Revert the button text after a short delay
|
|
setTimeout(function () {
|
|
button.innerHTML = originalText;
|
|
}, 2000);
|
|
}
|
|
|
|
function copyToClipboard(button) {
|
|
// Get the container element for all the message content
|
|
var messageContentContainer = button.closest('.message-bot').querySelector('#content-column .content');
|
|
|
|
// Get the text content of all the messages
|
|
var messageContent = messageContentContainer.textContent.trim();
|
|
|
|
// Create a temporary textarea element
|
|
var tempTextarea = document.createElement('textarea');
|
|
tempTextarea.value = messageContent;
|
|
|
|
// Append the temporary textarea to the document body
|
|
document.body.appendChild(tempTextarea);
|
|
|
|
// Select the text in the temporary textarea
|
|
tempTextarea.select();
|
|
|
|
// Copy the selected text to the clipboard
|
|
document.execCommand('copy');
|
|
|
|
// Remove the temporary textarea from the document body
|
|
document.body.removeChild(tempTextarea);
|
|
|
|
// Change the button text to indicate successful copy
|
|
var originalText = button.innerHTML;
|
|
button.innerHTML = '<i class="fa-solid fa-check"></i>';
|
|
|
|
// Revert the button text after a short delay
|
|
setTimeout(function () {
|
|
button.innerHTML = originalText;
|
|
}, 2000);
|
|
}
|
|
|
|
let lastSelectedIndex = null;
|
|
|
|
function toggleSelection(element) {
|
|
const elements = Array.from(document.getElementsByClassName('icon-llm'));
|
|
const index = elements.indexOf(element);
|
|
|
|
if (document.body.classList.contains('shift-pressed') && lastSelectedIndex !== null) {
|
|
const [start, end] = [lastSelectedIndex, index].sort((a, b) => a - b);
|
|
let allSelected = true;
|
|
for (let i = start; i <= end; i++) {
|
|
if (!elements[i].classList.contains('selected')) {
|
|
allSelected = false;
|
|
break;
|
|
}
|
|
}
|
|
for (let i = start; i <= end; i++) {
|
|
if (allSelected) {
|
|
elements[i].classList.remove('selected');
|
|
elements[i].classList.add('unselected');
|
|
} else {
|
|
elements[i].classList.add('selected');
|
|
elements[i].classList.remove('unselected');
|
|
}
|
|
}
|
|
lastSelectedIndex = null;
|
|
|
|
const elements2 = Array.from(document.getElementsByClassName('icon-text'));
|
|
for (let i = 0; i < elements2.length; i++) {
|
|
elements2[i].classList.remove('shiftselected');
|
|
}
|
|
} else if (document.body.classList.contains('shift-pressed') && lastSelectedIndex === null) {
|
|
lastSelectedIndex = index;
|
|
element.classList.toggle('shiftselected');
|
|
} else {
|
|
element.classList.toggle('selected');
|
|
element.classList.toggle('unselected');
|
|
}
|
|
|
|
// If at least one model is selected, enable the delete button
|
|
if (document.getElementsByClassName('selected icon-llm').length > 0) {
|
|
document.getElementById('delete-model-button').disabled = false;
|
|
} else {
|
|
document.getElementById('delete-model-button').disabled = true;
|
|
}
|
|
|
|
toggleSendButton();
|
|
}
|
|
|
|
function getSelectedModelsIDs() {
|
|
var selectedModelsIDs = [];
|
|
var selectedModels = document.getElementsByClassName('selected icon-llm');
|
|
for (var i = 0; i < selectedModels.length; i++) {
|
|
selectedModelsIDs.push(selectedModels[i].getAttribute('data-id'));
|
|
}
|
|
return selectedModelsIDs.length > 0 ? JSON.stringify(selectedModelsIDs) : '[]';
|
|
}
|
|
</script>
|
|
|
|
<script>
|
|
// Wait for a message-bot to appear in the chat and if so, delete the placeholder
|
|
// Select the node that will be observed for mutations
|
|
const targetNode = document.body;
|
|
|
|
// Options for the observer (which mutations to observe)
|
|
const config = { childList: true, subtree: true };
|
|
|
|
// Callback function to execute when mutations are observed
|
|
const callback = function (mutationsList, observer) {
|
|
for (let mutation of mutationsList) {
|
|
if (mutation.type === 'childList') {
|
|
for (let node of mutation.addedNodes) {
|
|
if (node.nodeType === 1 && node.classList.contains('message-bot') && !node.classList.contains('message-placeholder')) {
|
|
// A new element with the class "message-bot" has been added
|
|
// Remove the placeholder
|
|
const botPlaceholder = document.querySelector('.message-bot.message-placeholder');
|
|
if (botPlaceholder) {
|
|
botPlaceholder.remove();
|
|
}
|
|
const userPlaceholder = document.querySelector('.message-user.message-placeholder');
|
|
if (userPlaceholder) {
|
|
userPlaceholder.remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Create an observer instance linked to the callback function
|
|
const observer = new MutationObserver(callback);
|
|
|
|
// Start observing the target node for configured mutations
|
|
observer.observe(targetNode, config);
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html> |