chatgpt web frontend: no more using innerHTML. now using markdown-it instead of marked
This commit is contained in:
parent
6e93b90027
commit
a034a5a2b9
5 changed files with 121 additions and 93 deletions
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<!-- Include the JavaScript files at bottom to avoid blocking UI -->
|
||||
<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="controller.js" defer></script>
|
||||
</body>
|
||||
|
|
|
|||
2
api_webchat/markdown-it.min.js
vendored
Normal file
2
api_webchat/markdown-it.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
api_webchat/marked.min.js
vendored
6
api_webchat/marked.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,43 +1,69 @@
|
|||
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 {
|
||||
constructor() {
|
||||
super();
|
||||
const shadowRoot = this.attachShadow({mode: 'open'});
|
||||
const shadowRoot = this.attachShadow({ mode: 'open' });
|
||||
shadowRoot.appendChild(messageInputTemplate.content.cloneNode(true));
|
||||
|
||||
this._messageInputField = shadowRoot.querySelector('#messageInputField');
|
||||
|
|
@ -88,4 +114,5 @@ class MessageInput extends HTMLElement {
|
|||
this.worker.postMessage({ type: 'chatMessage', message: messageContent });
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('message-input', MessageInput);
|
||||
|
|
@ -1,52 +1,52 @@
|
|||
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 {
|
||||
display: inline; /* Tokens are inline elements */
|
||||
opacity: 0; /* Start with the token invisible */
|
||||
animation: fadeIn 1000ms forwards; /* Apply the fade-in animation */
|
||||
const messagesAreaStyle = document.createElement('style');
|
||||
messagesAreaStyle.textContent = `
|
||||
:host {
|
||||
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 {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<div id="messages"></div>
|
||||
}
|
||||
h2 {
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
margin-top: 20px;
|
||||
}
|
||||
`;
|
||||
messagesAreaTemplate.content.appendChild(messagesAreaStyle);
|
||||
|
||||
const messagesDiv = document.createElement('div');
|
||||
messagesDiv.id = 'messages';
|
||||
messagesAreaTemplate.content.appendChild(messagesDiv);
|
||||
|
||||
class MessagesArea extends HTMLElement {
|
||||
constructor() {
|
||||
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));
|
||||
|
||||
this.messages = shadowRoot.querySelector('#messages');
|
||||
|
|
@ -63,7 +63,7 @@ class MessagesArea extends HTMLElement {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -76,13 +76,13 @@ class MessagesArea extends HTMLElement {
|
|||
}
|
||||
|
||||
appendUserMessage(messageText, source="You") {
|
||||
console.log("appendUserMessage: "+messageText);
|
||||
console.log("appendUserMessage: " + messageText);
|
||||
const header = document.createElement('h2');
|
||||
header.textContent = source;
|
||||
this.messages.appendChild(header);
|
||||
|
||||
const messageElement = document.createElement('div');
|
||||
messageElement.classList.add('message', 'user'); // Tag as 'user' message
|
||||
messageElement.classList.add('message', 'user');
|
||||
messageElement.textContent = messageText;
|
||||
this.messages.appendChild(messageElement);
|
||||
this.scrollToBottom();
|
||||
|
|
@ -108,22 +108,27 @@ class MessagesArea extends HTMLElement {
|
|||
scrollToBottom() {
|
||||
this.messages.scrollTop = this.messages.scrollHeight;
|
||||
}
|
||||
|
||||
flushAccumulatingMessage() {
|
||||
if (this.accumulatingMessageEl) {
|
||||
// remove all the animation spans and interpret the text as markdown.
|
||||
// Raccogliere tutti i token in un testo completo
|
||||
let fullText = '';
|
||||
this.accumulatingMessageEl.querySelectorAll('.token').forEach(tokenEl => {
|
||||
fullText += tokenEl.textContent;
|
||||
});
|
||||
|
||||
// Convert Markdown to HTML
|
||||
let htmlText = marked.parse(fullText);
|
||||
console.log("htmlText: "+htmlText);
|
||||
this.accumulatingMessageEl.innerHTML = htmlText;
|
||||
// Convertire Markdown in nodi DOM usando la libreria markdown-it
|
||||
const md = window.markdownit();
|
||||
const html = md.render(fullText);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue