Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: updated ChatInput to a WYSIWYG editor to support Markdown and Codeblocks #1562

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

Mounayer
Copy link
Contributor

@Mounayer Mounayer commented Nov 12, 2024

Description

Closes #1545
Closes #1592

Updated the ChatInput component from using a textarea element into using a WYSIWYG editor by tiptap.

I first of all compared and contrasted all candidate tools for this task, and found that tiptap is the most svelte compatible out of them, additionally, tiptap is well supported and maintained.

I made sure to preserve the original functionality, everything behaves the same, including placeholders, and text submit. Any data submitted by the user is regular text. I reviewed how Claude works, and made sure the features implemented are very similar. Additionally, I also made sure to only include bold, italic, and codeblocks. For future references, tiptap also supports a bunch of other functionalities, such as images, tables, and others...

I also resulted to using lowlight for syntax highlighting which is based on highlight.js, particularly because tiptap has an extension that directly supports lowlight in its code blocks! So now the code blocks look clean and flashy!

I also fixed an issue in the MarkdownRenderer where markdown was being interpreted as a string rather than rendered html:

image

This was being caused by the escapeHTML function in the MarkdownRenderer which wasn't really needed since sanitization was being applied later on!

Examples

single codeblock

two codeblocks

submitted codeblock

I also made sure it is resizable and works on various screen sizes (if you really want to open up a codeblock and code in it on phone)
mobile responsiveness

text and codeblock

two codeblocks

User messages:

image

image

Usage

Upgraded features include:

  • Surrounding a word with **, or pressing ctrl + b before writing bolds a word
  • Surrounding a word with *, or pressing ctrl + i before writing italicizes a word
  • Doing three backticks "`" and pressing a space afterwards opens up a code block for you to write in!
  • User messages displayed using the MarkdownRenderer and editable

Testing

To test, I recommend trying all of the above mentioned features out. Try to italicize and bold at the same time, open code blocks, etc..

This is my first time working with Svelte, so let me know if any suggestions arise!

@nsarrazin nsarrazin added the front This issue is related to the front-end of the app. label Nov 12, 2024
Copy link
Collaborator

@nsarrazin nsarrazin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this PR, thanks a lot for the contrib, it would make a great addition!

A couple of comments:

  • When we apply markdown like italic, bold or even code blocks, it looks like they get removed in the sent message and only text is sent. (*Hi* becomes Hi in the prompt) I think a lot of people expect markdown elements to be passed to the LLM, so would it be possible to pass them directly?

  • Love the code blocks, but i was a bit confused by the behaviour for starting them. If i start a codeblock with ``` and then exit it by going down with the arrow, if I start another codeblock with ``` and then shift+enter, it doesnt start a codeblock.
    image

  • Would be nice to support inline code like this too if possible

  • Could we extract the editor component into a separate component? I think there's a few other places in the app where we would need this functionality and it would be nice to reuse the same editor everywhere.

  • Would it be easy to reuse the same style we use for highlight.js already for consistency? https://github.com/Mounayer/chat-ui/blob/e06910495bf7773a9f25b4c4be416c9c8effe12a/src/styles/highlight-js.css#L1-L2

Overall this is super nice, if you think we could get those changes in that would be great, let me know if you need help on those. 🚀

@Mounayer
Copy link
Contributor Author

I really like this PR, thanks a lot for the contrib, it would make a great addition!

A couple of comments:

  • When we apply markdown like italic, bold or even code blocks, it looks like they get removed in the sent message and only text is sent. (*Hi* becomes Hi in the prompt) I think a lot of people expect markdown elements to be passed to the LLM, so would it be possible to pass them directly?
  • Love the code blocks, but i was a bit confused by the behaviour for starting them. If i start a codeblock with and then exit it by going down with the arrow, if I start another codeblock with and then shift+enter, it doesnt start a codeblock.
    image
  • Would be nice to support inline code like this too if possible
  • Could we extract the editor component into a separate component? I think there's a few other places in the app where we would need this functionality and it would be nice to reuse the same editor everywhere.
  • Would it be easy to reuse the same style we use for highlight.js already for consistency? https://github.com/Mounayer/chat-ui/blob/e06910495bf7773a9f25b4c4be416c9c8effe12a/src/styles/highlight-js.css#L1-L2

Overall this is super nice, if you think we could get those changes in that would be great, let me know if you need help on those. 🚀

Thank you for your review @nsarrazin , let me address your requests:

  • For passing markdown elements to the LLM, I personally thought you'd only like to make the input field similar to Claude, not the sent message display as well! Would you like me to figure out a way to display the sent messages as markdown as well? The editor works in such a way that it can return the data entered either as regular text or as the created elements -- for example, if you write Hello, what really happens is that a paragraph element gets created!
  • Thank you for catching this edge case! This should not be a big deal, I'll work on it at once!
  • I'm pretty sure I can figure out a way to support inline code!
  • We can definitely extract the editor as its own component!
  • I'm going to attempt to use the actual atom-one-dark theme. But if that was not possible, would it be okay if I customized the colors to look exactly the same as the theme?

I'll work on these changes at once, thanks again for your review, and I'd appreciate if you could provide more information regarding the first point!

@Mounayer
Copy link
Contributor Author

Hey @nsarrazin !

I have updated the following:

  • Fixed Shift + Enter not working, additionally, I added support for languages, i.e., you don't have to open an empty codeblock with no chosen language anymore, you can choose one such as: ```cpp, creating an empty code block with no selected language works too, this would make lowlight automatically detect the syntax and highlight it appropriately.
  • I've added support to inline code blocks and it works great!
  • I have extracted the editor component into its own file so that it may be reused by other components in the future.
  • I have set the theme for the codeblocks to be the already setup atom-one-dark highlight.js theme

Here are some spoilers!
1
2
3

Matter of fact, it now looks identical to claude's:

image

Now the one thing I haven't touched yet is your last comment, which is regarding sending markdown to the llm, I was under the assumption this issue is only for adding markdown support in the input element, not also displaying messages and/or history as markdown! Would you like me to try to make that work as well? or should that be another issue?

Either way, I'm really happy to help, this was so much fun! And please, should you have any suggestions and/or ideas to improve, let me know!

@nsarrazin
Copy link
Collaborator

Hey @Mounayer thanks for adding the changes looks great! Couple more things:

  • What I meant was that if I type hello **bold** then the prompt passed to the model should be hello **bold** but right now it's only hello bold that gets passed. Do you think that would be doable ? Actually rendering it as markdown is optional but at least the raw text should be passed including the tags.

  • When I type a message in a conversation that already exists (so 2nd user message in a conversation) the input field does not get cleared after I send the message

Love the new style thanks 😁

@Mounayer
Copy link
Contributor Author

Hey @Mounayer thanks for adding the changes looks great! Couple more things:

  • What I meant was that if I type hello **bold** then the prompt passed to the model should be hello **bold** but right now it's only hello bold that gets passed. Do you think that would be doable ? Actually rendering it as markdown is optional but at least the raw text should be passed including the tags.
  • When I type a message in a conversation that already exists (so 2nd user message in a conversation) the input field does not get cleared after I send the message

Love the new style thanks 😁

Glad to help!

  • I understand now, you want the text passed to the LLM be markdown syntax but in text format! I'm not sure if tiptap supports this, if it doesn't I might have to getHTML and then simply replace some of the elements with the appropriate markdown syntax before passing it to the LLM as a text!
  • This is weird, I'll investigate at once!

@Mounayer
Copy link
Contributor Author

Hi @nsarrazin !

This was much easier than expected, gotta love how many extensions there are for tiptap ! I found one called tiptap-markdown that does precisely what you are asking for! Implementing it was relatively straightforward!

I also read through the tiptap docs and found a built-in function that not only empties the entire document, but also emits an update event! So now it should be working as expected (hopefully!)

Here are some images of the behvavior:
1
2
3

And the result (what is being sent):

4

I'm also going to try and figure out if there's anything we missed while waiting your response!

@Mounayer
Copy link
Contributor Author

Mounayer commented Nov 15, 2024

Hi @nsarrazin !

This was much easier than expected, gotta love how many extensions there are for tiptap ! I found one called tiptap-markdown that does precisely what you are asking for! Implementing it was relatively straightforward!

I also read through the tiptap docs and found a built-in function that not only empties the entire document, but also emits an update event! So now it should be working as expected (hopefully!)

Here are some images of the behvavior: 1 2 3

And the result (what is being sent):

4

I'm also going to try and figure out if there's anything we missed while waiting your response!

I've tested quite a lot and used more than one model, it works great, there is just one thing I've noticed. Newlines translate to \ since tiptap is returning everything in markdown, however, once the message display component starts using some sort of a markdown parser, this problem is automatically resolved! I'd also love to work on that issue as well!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
front This issue is related to the front-end of the app.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Markdown support for user messages Support markdown & code blocks in text input
2 participants