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,43 +1,69 @@
const messageInputTemplate = document.createElement('template'); const messageInputTemplate = document.createElement('template');
messageInputTemplate.innerHTML = `
<style>
:host {
display: flex;
justify-content: space-between;
align-items: center;
height: 24px;
margin: var(--margin);
margin-bottom: 20px;
}
#messageInputField {
flex-grow: 1;
padding: 10px; /* Increased padding */
font-size: 1rem; /* Adjusted font size to match message output */
border: 1px solid lightgrey; /* Light grey border */
border-radius: 10px; /* More rounded edges */
margin-right: var(--padding);
outline: none;
}
#messageInputField:focus {
border-color: darkgrey; /* Dark grey border on focus */
}
#sendButton {
width: 44px;
height: 36px;
cursor: pointer;
border-radius: 10px;
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>
`;
// 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> const messagesInputStyle = document.createElement('style');
messagesInputStyle .textContent = `
:host {
display: flex;
justify-content: space-between;
align-items: center;
height: 24px;
margin: var(--margin);
margin-bottom: 20px;
}
#messageInputField {
flex-grow: 1;
padding: 10px;
font-size: 1rem;
border: 1px solid lightgrey;
border-radius: 10px;
margin-right: var(--padding);
outline: none;
}
#messageInputField:focus {
border-color: darkgrey;
}
#sendButton {
width: 44px;
height: 36px;
cursor: pointer;
border-radius: 10px;
border: 2px solid darkgrey;
}
`;
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);
class MessageInput extends HTMLElement { class MessageInput extends HTMLElement {
constructor() { constructor() {
super(); super();
const shadowRoot = this.attachShadow({mode: 'open'}); const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(messageInputTemplate.content.cloneNode(true)); shadowRoot.appendChild(messageInputTemplate.content.cloneNode(true));
this._messageInputField = shadowRoot.querySelector('#messageInputField'); this._messageInputField = shadowRoot.querySelector('#messageInputField');
@ -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,52 +1,52 @@
const messagesAreaTemplate = document.createElement('template'); const messagesAreaTemplate = document.createElement('template');
messagesAreaTemplate.innerHTML = `
<style>
:host {
display: flex;
flex-direction: column;
height: 100%; /* Adjust as needed */
overflow-y: auto; /* Makes the area scrollable */
}
#messages {
display: flex;
flex-direction: column;
justify-content: flex-end; /* Align messages to the bottom */
min-height: 100%; /* Ensure it takes the full height */
margin: var(--margin);
}
.message {
margin-bottom: var(--margin);
line-height: 1.3;
}
.token { const messagesAreaStyle = document.createElement('style');
display: inline; /* Tokens are inline elements */ messagesAreaStyle.textContent = `
opacity: 0; /* Start with the token invisible */ :host {
animation: fadeIn 1000ms forwards; /* Apply the fade-in animation */ display: flex;
flex-direction: column;
height: 100%;
overflow-y: auto;
}
#messages {
display: flex;
flex-direction: column;
justify-content: flex-end;
min-height: 100%;
margin: var(--margin);
}
.message {
margin-bottom: var(--margin);
line-height: 1.3;
}
.token {
display: inline;
opacity: 0;
animation: fadeIn 1000ms forwards;
}
@keyframes fadeIn {
to {
opacity: 1;
} }
@keyframes fadeIn { }
to { h2 {
opacity: 1; font-weight: bold;
} font-size: 1rem;
} margin-top: 20px;
h2 { }
font-weight: bold;
font-size: 1rem;
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));
this.messages = shadowRoot.querySelector('#messages'); this.messages = shadowRoot.querySelector('#messages');
@ -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);
} }
@ -76,13 +76,13 @@ class MessagesArea extends HTMLElement {
} }
appendUserMessage(messageText, source="You") { appendUserMessage(messageText, source="You") {
console.log("appendUserMessage: "+messageText); console.log("appendUserMessage: " + messageText);
const header = document.createElement('h2'); const header = document.createElement('h2');
header.textContent = source; header.textContent = source;
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();
} }
} }