Sometimes rendering LLM outputs simply means taking the response text and shoving it inside a paragraph:
function LLMOutput({ children }) {
return <p>{children}</p>
}
This works for simple LLM response like "What's your favorite color" but maybe it's not the best solutions for a question like "Explain the reasons that brought us WW1". Complicated topics cannot be well represented by a simple paragraph, in fact if you ask this questions to ChatGPT this is the output:
World War I was ignited by a complex mix of political, economic, and social factors that had been building for years. Key reasons include:
1. **Alliances**: European nations had formed tangled alliances for protection. Germany allied with Austria-Hungary and Italy (Triple Alliance), while France, Russia, and Britain formed the Triple Entente. These alliances created a precarious balance where conflict between two countries could draw in many others.
2. **Nationalism**: Intense pride and competition among European nations fueled tensions. Nationalistic fervor often led to a desire for dominance, particularly in regions like the Balkans, where Slavic nationalism threatened Austria-Hungary's stability.
[...]
If you put this text inside a paragraph it would look pretty bad, that's where Markdown rendering can help you. Let's install a markdown-to-jsx to help us render markdown with React:
npm i markdown-to-jsx
# pnpm add markdown-to-jsx
# yarn add markdown-to-jsx
Then just swap the p
tag with the Markdown
component:
import Markdown from 'markdown-to-jsx';
function LLMOutout({ text }) {
return <Markdown>{text}</Markdown>
}
With this simple change, the response is rendered as an expressive document with numbered lists and bold keywords. Beautiful, but we can go further. There is no slideshow syntax in markdown so how do we render this? Half of the answer is in this modified prompt:
Explain the reasons that brought us WW1.
Instead of rendering the reasons as a list, use the Slideshow component like in this example:
'''
# My slides
Below this text, a slideshow will appear ๐ช
<Slideshow slides={[{ "id": 1, text: "first slide" },{ "id": 2, text: "second slide" }]}
'''
Here is an answer that ChatGPT gave me with this query:
# Causes of World War I
Below this text, a slideshow will appear :magic:
<Slideshow slides={[
{ "id": 1, "text": "The Rise of Nationalism: National pride and competitive fervor among nations fueled tension. Countries like Germany, France, and Britain were proud of their military power and colonial empires, creating a rivalry that would later ignite conflict." },
{ "id": 2, "text": "The Alliance System: European powers formed alliances for mutual protection. Two major blocs emergedโthe Triple Entente (France, Russia, Britain) and the Triple Alliance (Germany, Austria-Hungary, Italy). This network of alliances meant that a conflict between two countries could easily escalate." },
{ "id": 3, "text": "Militarization and Arms Race: With militarization on the rise, nations were investing heavily in their armies and navies. Germany and Britain especially competed in a naval arms race, creating massive fleets, which fostered distrust and prepared them for war." },
{ "id": 4, "text": "Imperialism: European powers were vying for colonial dominance, leading to conflicts in Africa, Asia, and the Balkans. This imperial competition heightened tensions and fueled a sense of entitlement and rivalry among nations." },
{ "id": 5, "text": "The Assassination of Archduke Franz Ferdinand: On June 28, 1914, the assassination of Austria-Hungaryโs heir in Sarajevo by a Bosnian Serb nationalist triggered a chain reaction. Austria-Hungaryโs ultimatum to Serbia led to a series of declarations of war, dragging the allied powers into conflict." }
]} />
This is great but how do we actually render the slideshow?
The answer is HTML tag overrides! Let's pass some options to the Markdown component to include an override for the non-existent "Slideshow" tag:
import Markdown from "markdown-to-jsx";
const options = {
overrides: {
Slideshow: {
component: Slideshow,
},
},
};
function LLMOutput({ children }) {
return <Markdown options={options}>{children}</Markdown>;
}
function Slideshow({ slides }) {
return (
<div>
<p>This is not a slideshow but you get the point</p>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(slides, null, 2)}
</pre>
</div>
);
}
Et Vue-a-Lร , or whatever they say at the end of front-end blogs ๐
Closing notes
- It seems like you can do this also with react-markdown
- If you want to play with this you can fork this repo i made
- For streaming i recommend accumulating chunks and flushing state updates on newlines
Top comments (0)