chatgpt web frontend: no more using innerHTML. now using markdown-it instead of marked

This commit is contained in:
mic 2024-07-21 00:18:41 +02:00
parent 6e93b90027
commit a034a5a2b9
5 changed files with 121 additions and 93 deletions

View file

@ -14,7 +14,7 @@
<!-- Include the JavaScript files at bottom to avoid blocking UI --> <!-- Include the JavaScript files at bottom to avoid blocking UI -->
<script src="messageInput.js" defer></script> <script src="messageInput.js" defer></script>
<script src="marked.min.js"></script> <script src="markdown-it.min.js"></script>
<script src="messagesArea.js" defer></script> <script src="messagesArea.js" defer></script>
<script src="controller.js" defer></script> <script src="controller.js" defer></script>
</body> </body>

2
api_webchat/markdown-it.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
const messageInputTemplate = document.createElement('template'); const messageInputTemplate = document.createElement('template');
messageInputTemplate.innerHTML = `
<style> const messagesInputStyle = document.createElement('style');
messagesInputStyle .textContent = `
:host { :host {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -11,15 +12,15 @@ messageInputTemplate.innerHTML = `
} }
#messageInputField { #messageInputField {
flex-grow: 1; flex-grow: 1;
padding: 10px; /* Increased padding */ padding: 10px;
font-size: 1rem; /* Adjusted font size to match message output */ font-size: 1rem;
border: 1px solid lightgrey; /* Light grey border */ border: 1px solid lightgrey;
border-radius: 10px; /* More rounded edges */ border-radius: 10px;
margin-right: var(--padding); margin-right: var(--padding);
outline: none; outline: none;
} }
#messageInputField:focus { #messageInputField:focus {
border-color: darkgrey; /* Dark grey border on focus */ border-color: darkgrey;
} }
#sendButton { #sendButton {
width: 44px; width: 44px;
@ -28,12 +29,37 @@ messageInputTemplate.innerHTML = `
border-radius: 10px; border-radius: 10px;
border: 2px solid darkgrey; border: 2px solid darkgrey;
} }
</style>
<input type="text" id="messageInputField" placeholder="" focus="true" autocomplete="off">
<button id="sendButton"><span class="" height="24" width="24" data-state="closed"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-white dark:text-black"><path d="M7 11L12 6L17 11M12 18V7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></span></button>
`; `;
messageInputTemplate.content.appendChild(messagesInputStyle);
const inputField = document.createElement('input');
inputField.type = 'text';
inputField.id = 'messageInputField';
inputField.placeholder = '';
inputField.autocomplete = 'off';
messageInputTemplate.content.appendChild(inputField);
const sendButton = document.createElement('button');
sendButton.id = 'sendButton';
const sendIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
sendIcon.setAttribute('width', '24');
sendIcon.setAttribute('height', '24');
sendIcon.setAttribute('viewBox', '0 0 24 24');
sendIcon.setAttribute('fill', 'none');
sendIcon.classList.add('text-white', 'dark:text-black');
const sendPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
sendPath.setAttribute('d', 'M7 11L12 6L17 11M12 18V7');
sendPath.setAttribute('stroke', 'currentColor');
sendPath.setAttribute('stroke-width', '2');
sendPath.setAttribute('stroke-linecap', 'round');
sendPath.setAttribute('stroke-linejoin', 'round');
sendIcon.appendChild(sendPath);
sendButton.appendChild(sendIcon);
messageInputTemplate.content.appendChild(sendButton);
// stop button <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="h-2 w-2 text-gizmo-gray-950 dark:text-gray-200" height="16" width="16"><path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2z" stroke-width="0"></path></svg>
class MessageInput extends HTMLElement { class MessageInput extends HTMLElement {
constructor() { constructor() {
super(); super();
@ -88,4 +114,5 @@ class MessageInput extends HTMLElement {
this.worker.postMessage({ type: 'chatMessage', message: messageContent }); this.worker.postMessage({ type: 'chatMessage', message: messageContent });
} }
} }
customElements.define('message-input', MessageInput); customElements.define('message-input', MessageInput);

View file

@ -1,28 +1,28 @@
const messagesAreaTemplate = document.createElement('template'); const messagesAreaTemplate = document.createElement('template');
messagesAreaTemplate.innerHTML = `
<style> const messagesAreaStyle = document.createElement('style');
messagesAreaStyle.textContent = `
:host { :host {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; /* Adjust as needed */ height: 100%;
overflow-y: auto; /* Makes the area scrollable */ overflow-y: auto;
} }
#messages { #messages {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; /* Align messages to the bottom */ justify-content: flex-end;
min-height: 100%; /* Ensure it takes the full height */ min-height: 100%;
margin: var(--margin); margin: var(--margin);
} }
.message { .message {
margin-bottom: var(--margin); margin-bottom: var(--margin);
line-height: 1.3; line-height: 1.3;
} }
.token { .token {
display: inline; /* Tokens are inline elements */ display: inline;
opacity: 0; /* Start with the token invisible */ opacity: 0;
animation: fadeIn 1000ms forwards; /* Apply the fade-in animation */ animation: fadeIn 1000ms forwards;
} }
@keyframes fadeIn { @keyframes fadeIn {
to { to {
@ -34,17 +34,17 @@ messagesAreaTemplate.innerHTML = `
font-size: 1rem; font-size: 1rem;
margin-top: 20px; margin-top: 20px;
} }
</style>
<div id="messages"></div>
`; `;
messagesAreaTemplate.content.appendChild(messagesAreaStyle);
const messagesDiv = document.createElement('div');
messagesDiv.id = 'messages';
messagesAreaTemplate.content.appendChild(messagesDiv);
class MessagesArea extends HTMLElement { class MessagesArea extends HTMLElement {
constructor() { constructor() {
super(); super();
this.accumulatingMessageEl = null; // No initial message container this.accumulatingMessageEl = null;
const shadowRoot = this.attachShadow({ mode: 'open' }); const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(messagesAreaTemplate.content.cloneNode(true)); shadowRoot.appendChild(messagesAreaTemplate.content.cloneNode(true));
@ -63,7 +63,7 @@ class MessagesArea extends HTMLElement {
} }
this.accumulatingMessageEl = document.createElement('div'); this.accumulatingMessageEl = document.createElement('div');
this.accumulatingMessageEl.classList.add('message', 'bot'); // Tag as 'bot' message this.accumulatingMessageEl.classList.add('message', 'bot');
this.messages.appendChild(this.accumulatingMessageEl); this.messages.appendChild(this.accumulatingMessageEl);
} }
@ -82,7 +82,7 @@ class MessagesArea extends HTMLElement {
this.messages.appendChild(header); this.messages.appendChild(header);
const messageElement = document.createElement('div'); const messageElement = document.createElement('div');
messageElement.classList.add('message', 'user'); // Tag as 'user' message messageElement.classList.add('message', 'user');
messageElement.textContent = messageText; messageElement.textContent = messageText;
this.messages.appendChild(messageElement); this.messages.appendChild(messageElement);
this.scrollToBottom(); this.scrollToBottom();
@ -108,22 +108,27 @@ class MessagesArea extends HTMLElement {
scrollToBottom() { scrollToBottom() {
this.messages.scrollTop = this.messages.scrollHeight; this.messages.scrollTop = this.messages.scrollHeight;
} }
flushAccumulatingMessage() { flushAccumulatingMessage() {
if (this.accumulatingMessageEl) { if (this.accumulatingMessageEl) {
// remove all the animation spans and interpret the text as markdown. // Raccogliere tutti i token in un testo completo
let fullText = ''; let fullText = '';
this.accumulatingMessageEl.querySelectorAll('.token').forEach(tokenEl => { this.accumulatingMessageEl.querySelectorAll('.token').forEach(tokenEl => {
fullText += tokenEl.textContent; fullText += tokenEl.textContent;
}); });
// Convert Markdown to HTML // Convertire Markdown in nodi DOM usando la libreria markdown-it
let htmlText = marked.parse(fullText); const md = window.markdownit();
console.log("htmlText: "+htmlText); const html = md.render(fullText);
this.accumulatingMessageEl.innerHTML = htmlText; const tempDiv = document.createElement('div');
tempDiv.innerHTML = html;
this.accumulatingMessageEl.innerHTML = ''; // Rimuovere i token esistenti
Array.from(tempDiv.childNodes).forEach(node => {
this.accumulatingMessageEl.appendChild(node);
});
this.accumulatingMessageEl = null; // Clear the reference for the next message this.accumulatingMessageEl = null;
} }
//this.scrollToBottom();
} }
} }