Skip to content

Commit

Permalink
improve markdown rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
cornelcroi committed Oct 11, 2024
1 parent b12fafc commit ee89339
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 162 deletions.
4 changes: 2 additions & 2 deletions examples/chat-demo-app/ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions examples/chat-demo-app/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"react-dom": "^18.3.1",
"react-markdown": "^9.0.1",
"react-syntax-highlighter": "^15.5.0",
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.0",
"typescript": "^5.6.2",
"uuid": "^10.0.0"
},
Expand Down
95 changes: 50 additions & 45 deletions examples/chat-demo-app/ui/src/components/ChatWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,53 @@ import '@aws-amplify/ui-react/styles.css';
import { configureAmplify } from '../utils/amplifyConfig';
import { replaceTextEmotesWithEmojis } from './emojiHelper';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
import LoadingScreen from '../components/loadingScreen';

const MarkdownRenderer: React.FC<{ content: string }> = ({ content }) => {
useEffect(() => {
hljs.highlightAll();
}, [content]);

return (
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw]}
components={{
code({ node, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return match ? (
<pre className="bg-yellow-50 rounded-md p-4 my-2 overflow-x-auto text-sm font-mono">
<code className={className} {...props}>
{children}
</code>
</pre>
) : (
<code className="bg-yellow-100 text-yellow-900 px-1 rounded font-mono" {...props}>
{children}
</code>
);
},
p: ({ node, ...props }) => <p className="mb-2" {...props} />,
a: ({ node, ...props }) => <a className="text-blue-600 hover:underline" target="_blank" rel="noopener noreferrer" {...props} />,
h1: ({ node, ...props }) => <h1 className="text-2xl font-bold mt-4 mb-2" {...props} />,
h2: ({ node, ...props }) => <h2 className="text-xl font-bold mt-3 mb-2" {...props} />,
h3: ({ node, ...props }) => <h3 className="text-lg font-bold mt-2 mb-1" {...props} />,
ul: ({ node, ...props }) => <ul className="list-disc list-inside mb-2 pl-4" {...props} />,
ol: ({ node, ...props }) => <ol className="list-decimal mb-2 pl-6" {...props} />,
li: ({ node, ...props }) => <li className="mb-1" {...props} />,
blockquote: ({ node, ...props }) => <blockquote className="border-l-4 border-yellow-300 pl-4 italic my-2" {...props} />,
}}
className="markdown-content text-yellow-900"
>
{content}
</ReactMarkdown>
);
};

const ChatWindow: React.FC = () => {
const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null);
const [messages, setMessages] = useState<Array<any>>([]);
Expand All @@ -20,7 +65,6 @@ const ChatWindow: React.FC = () => {
const [client, setClient] = useState<ReturnType<any> | null>(null);
const [responseReceived, setResponseReceived] = useState(false);


const createAuthenticatedClient = async () => {
return new ChatApiClient();
};
Expand Down Expand Up @@ -62,53 +106,13 @@ const ChatWindow: React.FC = () => {
}, []);


interface CodeBlockProps {
value: string;
}

const CodeBlock: React.FC<CodeBlockProps> = ({ value }) => {
return (
<pre className="bg-gray-100 rounded-md p-4 my-2 overflow-x-auto text-sm font-mono">
<code>{value}</code>
</pre>
);
};

const renderMessageContent = (content: string) => {
const processedContent = replaceTextEmotesWithEmojis(content);
return (
<ReactMarkdown
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
const isMultiLine = String(children).includes('\n');

if (!inline && (match || isMultiLine)) {
return <CodeBlock value={String(children).replace(/\n$/, '')} {...props} />;
}

return (
<code className="bg-yellow-100 text-yellow-900 px-1 rounded font-mono" {...props}>
{children}
</code>
);
},
p: ({ node, ...props }) => <p className="mb-2" {...props} />,
a: ({ node, ...props }) => <a className="text-blue-600 hover:underline" target="_blank" rel="noopener noreferrer" {...props} />,
h1: ({ node, ...props }) => <h1 className="text-2xl font-bold mt-4 mb-2" {...props} />,
h2: ({ node, ...props }) => <h2 className="text-xl font-bold mt-3 mb-2" {...props} />,
h3: ({ node, ...props }) => <h3 className="text-lg font-bold mt-2 mb-1" {...props} />,
ul: ({ node, ...props }) => <ul className="list-disc list-inside mb-2 pl-4" {...props} />,
ol: ({ node, ...props }) => <ol className="list-decimal mb-2 pl-6" {...props} />,
li: ({ node, ...props }) => <li className="mb-1" {...props} />,
blockquote: ({ node, ...props }) => <blockquote className="border-l-4 border-gray-300 pl-4 italic my-2" {...props} />,
}}
className="markdown-content text-gray-800"
>
{processedContent}
</ReactMarkdown>
);
return <MarkdownRenderer content={processedContent} />;
};



useEffect(() => {
Expand Down Expand Up @@ -193,7 +197,8 @@ const ChatWindow: React.FC = () => {
if (done) break;

const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.trim() !== '');
//console.log("chunk="+chunk)
const lines = chunk.split('\n');

for (const line of lines) {
try {
Expand All @@ -211,7 +216,7 @@ const ChatWindow: React.FC = () => {
accumulatedContent += `Error: ${parsedLine.data}\n`;
break;
}
console.log(accumulatedContent)

setMessages(prevMessages => [
...prevMessages.slice(0, -1),
{
Expand Down
164 changes: 49 additions & 115 deletions examples/chat-demo-app/ui/src/components/emojiHelper.ts
Original file line number Diff line number Diff line change
@@ -1,118 +1,52 @@
const emojiMap: Record<string, string> = {
// Smiles and positive emotions
'sourit': '😊',
'smiles': '😊',
'rit': '😄',
'laughs': '😄',
'rire aux éclats': '🤣',
'laughs out loud': '🤣',
'clin d\'oeil': '😉',
'winks': '😉',
'warmly': '🤗',
'chaleureusement': '🤗',
'excité': '😃',
'excited': '😃',
'heureux': '😄',
'happy': '😄',
'joyeux': '😊',
'joyful': '😊',

// Thinking and pondering
'réfléchit': '🤔',
'thinks': '🤔',
'pense': '💭',
'ponders': '💭',
'curieux': '🧐',
'curious': '🧐',

// Negative emotions
'triste': '😢',
'sad': '😢',
'inquiet': '😟',
'worried': '😟',
'confus': '😕',
'confused': '😕',
'frustré': '😤',
'frustrated': '😤',
'en colère': '😠',
'angry': '😠',

// Surprise and shock
'surpris': '😮',
'surprised': '😮',
'choqué': '😱',
'shocked': '😱',
'bouche bée': '😲',
'jaw drops': '😲',

// Gestures and actions
'hoche la tête': '🙂',
'nods': '🙂',
'fronce les sourcils': '😟',
'frowns': '😟',
'soupire': '😮‍💨',
'sighs': '😮‍💨',
'applaudit': '👏',
'applauds': '👏',
'pouce en l\'air': '👍',
'thumbs up': '👍',
'pouce en bas': '👎',
'thumbs down': '👎',
'lève la main': '🙋',
'raises hand': '🙋',

// Miscellaneous
'cœur': '❤️',
'heart': '❤️',
'cligne des yeux': '😳',
'blinks': '😳',
'bâille': '🥱',
'yawns': '🥱',
'dort': '😴',
'sleeps': '😴',
'rêve': '💤',
'dreams': '💤',
'réfléchit profondément': '🧠',
'thinks deeply': '🧠',
'a une idée': '💡',
'has an idea': '💡',
'fête': '🎉',
'celebrates': '🎉',

// Sarcasm and humor
'sarcastic': '😏',
'sarcastique': '😏',
'rolls eyes': '🙄',
'lève les yeux au ciel': '🙄',
'plaisante': '😜',
'jokes': '😜',

// Professional and formal
'serre la main': '🤝',
'shakes hands': '🤝',
'salue': '👋',
'waves': '👋',
'présente': '👨‍🏫',
'presents': '👨‍🏫',
'cheerfully': '😄',
'gaiement': '😄',
'joyeusement': '😄',

// Technology and modern life
'tape sur le clavier': '⌨️',
'types': '⌨️',
'prend une photo': '📸',
'takes a photo': '📸',
'regarde son téléphone': '📱',
'checks phone': '📱'
};
// Smiles and positive emotions
':)': '😊',
':-)': '😊',
':D': '😄',
':-D': '😄',
'XD': '🤣',
';)': '😉',
';-)': '😉',
':>': '😃',
':->': '😃',

const defaultEmoji = '🌟'; // Using a star emoji as default
// Negative emotions
':(': '😢',
':-(': '😢',
':/': '😕',
':-/': '😕',
':@': '😠',
':-@': '😠',

// Surprise and shock
':o': '😮',
':-o': '😮',
':O': '😱',
':-O': '😱',

// Other expressions
':p': '😛',
':-p': '😛',
':P': '😛',
':-P': '😛',
':|': '😐',
':-|': '😐',
':3': '😊',

// Additional emotes
'<3': '❤️',
'^_^': '😊',
'-_-': '😑',
'o_o': '😳',
'O_O': '😳',
'T_T': '😭',
'¬_¬': '😒',
};

export function replaceTextEmotesWithEmojis(text: string): string {
return text.replace(/\*(.*?)\*/g, (match, p1) => {
const lowercaseEmote = p1.toLowerCase().trim();
return emojiMap[lowercaseEmote] || defaultEmoji;
});
}
export function replaceTextEmotesWithEmojis(text: string): string {
const emoteRegex = /(?<=\s|^)[:;XD@OP3<>^T¬\-\/_o]+(?=\s|$)|(?<=\s|^)[()]+(?=\s|$)/g;

return text.replace(emoteRegex, (match) => {
return emojiMap[match] || match;
});
}

0 comments on commit ee89339

Please sign in to comment.