skip to Main Content

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


  1. Chosen as BEST ANSWER

    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


  2. You can append your HTML to innerHTML via the += operator and it will be evaluated as HTML:

    function getTemplate() {
        return "<p style='background-color: green;'>something</p>";
    }
    
    function addTemplate(div) {
        let txt = getTemplate();
        div.innerHTML += txt;
    }
    <div id="foo"></div>
    <input type="button" onclick="addTemplate(document.getElementById('foo'))"  value="add">

    If it does not happen like that for you, then you would need to provide a snippet where we can reproduce it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search