Skip to content

Commit 3f17df2

Browse files
committed
Adding markdown display support for text responses... sometimes LLMs return responses in markdown format
1 parent b4f46b7 commit 3f17df2

File tree

1 file changed

+316
-2
lines changed

1 file changed

+316
-2
lines changed

src/ui/src/components/document-analytics-layout/TextDisplay.jsx

Lines changed: 316 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,324 @@
33
import React from 'react';
44
import PropTypes from 'prop-types';
55
import { Box, Container, Header } from '@awsui/components-react';
6+
import ReactMarkdown from 'react-markdown';
7+
import remarkGfm from 'remark-gfm';
8+
import rehypeRaw from 'rehype-raw';
9+
10+
// Custom heading components with stronger inline styles
11+
const H1Component = ({ children }) => (
12+
<h1
13+
style={{
14+
fontSize: '1.75em',
15+
fontWeight: 'bold',
16+
color: '#232f3e',
17+
marginTop: '0.5em',
18+
marginBottom: '0.5em',
19+
lineHeight: '1.2',
20+
}}
21+
>
22+
{children}
23+
</h1>
24+
);
25+
26+
const H2Component = ({ children }) => (
27+
<h2
28+
style={{
29+
fontSize: '1.5em',
30+
fontWeight: 'bold',
31+
color: '#232f3e',
32+
marginTop: '0.75em',
33+
marginBottom: '0.5em',
34+
lineHeight: '1.3',
35+
}}
36+
>
37+
{children}
38+
</h2>
39+
);
40+
41+
const H3Component = ({ children }) => (
42+
<h3
43+
style={{
44+
fontSize: '1.25em',
45+
fontWeight: 'bold',
46+
color: '#232f3e',
47+
marginTop: '0.75em',
48+
marginBottom: '0.5em',
49+
lineHeight: '1.3',
50+
}}
51+
>
52+
{children}
53+
</h3>
54+
);
55+
56+
const H4Component = ({ children }) => (
57+
<h4
58+
style={{
59+
fontSize: '1.1em',
60+
fontWeight: 'bold',
61+
color: '#232f3e',
62+
marginTop: '0.75em',
63+
marginBottom: '0.5em',
64+
lineHeight: '1.3',
65+
}}
66+
>
67+
{children}
68+
</h4>
69+
);
70+
71+
const ParagraphComponent = ({ children }) => (
72+
<p
73+
style={{
74+
marginBottom: '1em',
75+
lineHeight: '1.6',
76+
color: '#16191f',
77+
}}
78+
>
79+
{children}
80+
</p>
81+
);
82+
83+
const CodeComponent = ({ inline, children }) => {
84+
if (inline) {
85+
return (
86+
<code
87+
style={{
88+
backgroundColor: '#f4f4f4',
89+
padding: '0.2em 0.4em',
90+
borderRadius: '3px',
91+
fontFamily: 'Monaco, Consolas, "Courier New", monospace',
92+
fontSize: '0.9em',
93+
color: '#d63384',
94+
}}
95+
>
96+
{children}
97+
</code>
98+
);
99+
}
100+
return (
101+
<code
102+
style={{
103+
fontFamily: 'Monaco, Consolas, "Courier New", monospace',
104+
fontSize: '0.9em',
105+
}}
106+
>
107+
{children}
108+
</code>
109+
);
110+
};
111+
112+
const PreComponent = ({ children }) => (
113+
<pre
114+
style={{
115+
backgroundColor: '#f8f9fa',
116+
border: '1px solid #e9ecef',
117+
padding: '1em',
118+
borderRadius: '5px',
119+
overflow: 'auto',
120+
marginBottom: '1em',
121+
fontFamily: 'Monaco, Consolas, "Courier New", monospace',
122+
fontSize: '0.9em',
123+
}}
124+
>
125+
{children}
126+
</pre>
127+
);
128+
129+
const UlComponent = ({ children }) => <ul style={{ marginBottom: '1em', paddingLeft: '2em' }}>{children}</ul>;
130+
131+
const OlComponent = ({ children }) => <ol style={{ marginBottom: '1em', paddingLeft: '2em' }}>{children}</ol>;
132+
133+
const LiComponent = ({ children }) => <li style={{ marginBottom: '0.25em' }}>{children}</li>;
134+
135+
const BlockquoteComponent = ({ children }) => (
136+
<blockquote
137+
style={{
138+
borderLeft: '4px solid #0073bb',
139+
paddingLeft: '1em',
140+
marginLeft: '0',
141+
marginBottom: '1em',
142+
fontStyle: 'italic',
143+
color: '#5f6368',
144+
}}
145+
>
146+
{children}
147+
</blockquote>
148+
);
149+
150+
const TableComponent = ({ children }) => (
151+
<table
152+
style={{
153+
borderCollapse: 'collapse',
154+
width: '100%',
155+
marginBottom: '1em',
156+
border: '1px solid #ddd',
157+
}}
158+
>
159+
{children}
160+
</table>
161+
);
162+
163+
const ThComponent = ({ children }) => (
164+
<th
165+
style={{
166+
border: '1px solid #ddd',
167+
padding: '0.5em',
168+
textAlign: 'left',
169+
backgroundColor: '#f2f2f2',
170+
fontWeight: 'bold',
171+
}}
172+
>
173+
{children}
174+
</th>
175+
);
176+
177+
const TdComponent = ({ children }) => (
178+
<td
179+
style={{
180+
border: '1px solid #ddd',
181+
padding: '0.5em',
182+
textAlign: 'left',
183+
}}
184+
>
185+
{children}
186+
</td>
187+
);
188+
189+
const LinkComponent = ({ children, href }) => (
190+
<a
191+
href={href}
192+
style={{
193+
color: '#0073bb',
194+
textDecoration: 'none',
195+
}}
196+
onMouseEnter={(e) => {
197+
e.target.style.textDecoration = 'underline';
198+
}}
199+
onMouseLeave={(e) => {
200+
e.target.style.textDecoration = 'none';
201+
}}
202+
>
203+
{children}
204+
</a>
205+
);
206+
207+
const StrongComponent = ({ children }) => <strong style={{ fontWeight: 'bold' }}>{children}</strong>;
208+
209+
const EmComponent = ({ children }) => <em style={{ fontStyle: 'italic' }}>{children}</em>;
210+
211+
// PropTypes for all components
212+
H1Component.propTypes = {
213+
children: PropTypes.node.isRequired,
214+
};
215+
216+
H2Component.propTypes = {
217+
children: PropTypes.node.isRequired,
218+
};
219+
220+
H3Component.propTypes = {
221+
children: PropTypes.node.isRequired,
222+
};
223+
224+
H4Component.propTypes = {
225+
children: PropTypes.node.isRequired,
226+
};
227+
228+
ParagraphComponent.propTypes = {
229+
children: PropTypes.node.isRequired,
230+
};
231+
232+
CodeComponent.propTypes = {
233+
inline: PropTypes.bool,
234+
children: PropTypes.node.isRequired,
235+
};
236+
237+
CodeComponent.defaultProps = {
238+
inline: false,
239+
};
240+
241+
PreComponent.propTypes = {
242+
children: PropTypes.node.isRequired,
243+
};
244+
245+
UlComponent.propTypes = {
246+
children: PropTypes.node.isRequired,
247+
};
248+
249+
OlComponent.propTypes = {
250+
children: PropTypes.node.isRequired,
251+
};
252+
253+
LiComponent.propTypes = {
254+
children: PropTypes.node.isRequired,
255+
};
256+
257+
BlockquoteComponent.propTypes = {
258+
children: PropTypes.node.isRequired,
259+
};
260+
261+
TableComponent.propTypes = {
262+
children: PropTypes.node.isRequired,
263+
};
264+
265+
ThComponent.propTypes = {
266+
children: PropTypes.node.isRequired,
267+
};
268+
269+
TdComponent.propTypes = {
270+
children: PropTypes.node.isRequired,
271+
};
272+
273+
LinkComponent.propTypes = {
274+
children: PropTypes.node.isRequired,
275+
href: PropTypes.string,
276+
};
277+
278+
LinkComponent.defaultProps = {
279+
href: '#',
280+
};
281+
282+
StrongComponent.propTypes = {
283+
children: PropTypes.node.isRequired,
284+
};
285+
286+
EmComponent.propTypes = {
287+
children: PropTypes.node.isRequired,
288+
};
6289

7290
const TextDisplay = ({ textData }) => {
8291
if (!textData || !textData.content) {
9292
return null;
10293
}
11294

295+
const markdownComponents = {
296+
h1: H1Component,
297+
h2: H2Component,
298+
h3: H3Component,
299+
h4: H4Component,
300+
p: ParagraphComponent,
301+
code: CodeComponent,
302+
pre: PreComponent,
303+
ul: UlComponent,
304+
ol: OlComponent,
305+
li: LiComponent,
306+
blockquote: BlockquoteComponent,
307+
table: TableComponent,
308+
th: ThComponent,
309+
td: TdComponent,
310+
a: LinkComponent,
311+
strong: StrongComponent,
312+
em: EmComponent,
313+
};
314+
12315
return (
13316
<Container header={<Header variant="h3">Text Response</Header>}>
14317
<Box padding="m">
15-
<Box variant="p" fontSize="body-m" padding="s" backgroundColor="background-container-content">
16-
{textData.content}
318+
<Box variant="div" fontSize="body-m" padding="s" backgroundColor="background-container-content">
319+
<div style={{ lineHeight: '1.6' }}>
320+
<ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]} components={markdownComponents}>
321+
{textData.content}
322+
</ReactMarkdown>
323+
</div>
17324
</Box>
18325
</Box>
19326
</Container>
@@ -27,6 +334,13 @@ TextDisplay.propTypes = {
27334
}),
28335
};
29336

337+
TextDisplay.propTypes = {
338+
textData: PropTypes.shape({
339+
content: PropTypes.string.isRequired,
340+
responseType: PropTypes.string,
341+
}),
342+
};
343+
30344
TextDisplay.defaultProps = {
31345
textData: null,
32346
};

0 commit comments

Comments
 (0)