Consider this simple code below
When I parse the content and get the "txt" with JSON.parse(e.data).choices[0].delta.content;
then it works fine if it is plain text. However, there are some simple HTML tags in the response like <strong>
etc. which don’t render as HTML in the browser.
I don’t know how to render it as it is. I realize that the chunks of data, when they arrive, may not have closing HTML tags in them and may also have incomplete HTML tags, but when the stream ends, then all is well usually.
How do I ensure that the browser treats the "txt" content as HTML and not as text? The variable thisWebPath is well set and does get streamed data back in JSON
Thanks in advance
function sendMsg(msg) {
var formData = new FormData();
formData.append('msg', msg);
formData.append('user_id', USER_ID);
fetch(thisWebPath + '/send-message.php', {method: 'POST', body: formData})
.then(response => response.json())
.then(data => {
let uuid = uuidv4()
const eventSource = new EventSource(thisWebPath + `/event-stream.php?chat_history_id=${data.id}&id=${encodeURIComponent(USER_ID)}`);
appendMessage(BOT_NAME, BOT_IMG, "left", "", uuid);
const div = document.getElementById(uuid);
eventSource.onmessage = function (e) {
if (e.data == "[DONE]") {
msgerSendBtn.disabled = false;
document.getElementById("userSendButtonAV").value="Send";
var elemB = document.getElementById("userSendButtonAV");
elemB.value = "Send";
document.getElementById('userMessageAV').placeholder='Enter your message now...';
document.getElementById('userMessageAV').disabled = false;
eventSource.close();
} else {
//original code let txt = JSON.parse(e.data).choices[0].delta.content
if (isJsonString(e.data)) {
let txt = JSON.parse(e.data).choices[0].delta.content;
if (txt !== undefined) {
div.innerHTML += txt.replace(/(?:rn|r|n)/g, '<br>');
}
}
}
};
eventSource.onerror = function (e) {
var elemC = document.getElementById("userSendButtonAV");
elemC.value = "Send";
msgerSendBtn.disabled = false;
document.getElementById('userMessageAV').placeholder='Enter your message now...';
document.getElementById('userMessageAV').disabled = false;
//console.log(e);
eventSource.close();
};
})
.catch(error => console.error(error));
}
I am expecting the text to be handled like HTML
Edit: this is how I am currently adding the message
function appendMessage(name, img, side, text, id) {
// Simple solution for small apps
const msgHTML = `
<div class="msg ${side}-msg">
<!--- div class="msg-img" style="background-image: url(${img})"></div --->
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">${name}</div>
<div class="msg-info-time">${formatDate(new Date())}</div>
</div>
<div class="msg-text" id=${id}>${text}</div>
</div>
</div>
`;
if ( typeof(text) !== "undefined" && text !== null ) {
msgerChat.insertAdjacentHTML("beforeend", msgHTML);
msgerChat.scrollTop += 500;
}
}
insertAdjacentText is a function, but that is even worse... it just writes out the entire text including the html code
Edited again:
The entire new div gets inside a main tag such as
<main class="msger-chat">
</main>
And even that gets dynamically generated, along with a bunch of other stuff, which is why insertAdjacentHtml is used
How can i simply append the content using innerHtml so that the new div that starts with the following gets added at the end of the "main" element"?
<div class="msg ${side}-msg">
Yet another edit. The issue is text/event-stream content type, so obviously the browser treats it as text 🙁 I saw the inspect network in chrome
Even if i add a utf-8 suffix to it, the browser still treats it as text and not as html. I think this is the main issue….
2
Answers
What i was trying was to get openAi to use HTML markdown instead of its standard markdown while streaming the response. Not ideal, as one could try injecting html. Debatable (if the backend source is trusted and verified, and no CORS, it is not an issue, BTW).
Besides, with streaming HTML, things were going haywire.
So, i decided to not use html in the streamed response, but go with openAi's use of the standard markdown
And, i just apply the markdown once the stream has finished, and not on the chunks, and it works fine. It looks a bit weird to the user as the format suddenly changes...but hey... should be ok
Solution at using showdown js with openAi streaming response
You can append your HTML to
innerHTML
via the+=
operator and it will be evaluated as HTML:If it does not happen like that for you, then you would need to provide a snippet where we can reproduce it.