Skip to content

Commit c66e195

Browse files
committed
reasoning model renderer support
1 parent ad5756a commit c66e195

File tree

2 files changed

+212
-4
lines changed

2 files changed

+212
-4
lines changed

src/components/MarkdownRender/markdown-without-katex.jsx

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,108 @@ import remarkGfm from 'remark-gfm'
55
import remarkBreaks from 'remark-breaks'
66
import { Pre } from './Pre'
77
import { Hyperlink } from './Hyperlink'
8-
import { memo } from 'react'
8+
import { memo, useState } from 'react'
9+
import { useTranslation } from 'react-i18next'
10+
11+
// eslint-disable-next-line
12+
const ThinkComponent = ({ node, children, ...props }) => {
13+
const { t } = useTranslation()
14+
const [isExpanded, setIsExpanded] = useState(true)
15+
const isEmpty =
16+
!children ||
17+
(Array.isArray(children) &&
18+
// eslint-disable-next-line
19+
(children.length === 0 ||
20+
// eslint-disable-next-line
21+
(children.length === 1 && typeof children[0] === 'string' && children[0].trim() === '')))
22+
23+
const toggleExpanded = () => {
24+
setIsExpanded(!isExpanded)
25+
}
26+
27+
return isEmpty ? (
28+
<></>
29+
) : (
30+
<div
31+
style={{
32+
marginBottom: '16px',
33+
borderRadius: '12px',
34+
border: '1px solid #e2e8f0',
35+
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.06)',
36+
overflow: 'hidden',
37+
transition: 'all 0.3s ease',
38+
}}
39+
>
40+
<div
41+
onClick={toggleExpanded}
42+
style={{
43+
cursor: 'pointer',
44+
padding: '12px 16px',
45+
borderBottom: isExpanded ? '1px solid rgba(255, 255, 255, 0.2)' : 'none',
46+
display: 'flex',
47+
alignItems: 'center',
48+
justifyContent: 'space-between',
49+
fontSize: '14px',
50+
fontWeight: '500',
51+
transition: 'all 0.3s ease',
52+
position: 'relative',
53+
}}
54+
>
55+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
56+
<span
57+
style={{
58+
display: 'inline-block',
59+
width: '6px',
60+
height: '6px',
61+
borderRadius: '50%',
62+
animation: isExpanded ? 'pulse 2s infinite' : 'none',
63+
}}
64+
/>
65+
<span style={{ fontSize: '13px', letterSpacing: '0.5px' }}>
66+
💭 {t('Thinking Content')}
67+
</span>
68+
</div>
69+
<div
70+
style={{
71+
transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',
72+
transition: 'transform 0.3s ease',
73+
fontSize: '12px',
74+
}}
75+
>
76+
77+
</div>
78+
</div>
79+
<div
80+
style={{
81+
maxHeight: isExpanded ? '1000px' : '0',
82+
overflow: 'hidden',
83+
transition: 'max-height 0.4s ease, padding 0.3s ease',
84+
padding: isExpanded ? '16px 20px' : '0 20px',
85+
borderTop: isExpanded ? '1px solid #e2e8f0' : 'none',
86+
}}
87+
>
88+
<div
89+
style={{
90+
whiteSpace: 'pre-wrap',
91+
fontSize: '13px',
92+
lineHeight: '1.6',
93+
fontFamily: '"SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace',
94+
opacity: isExpanded ? 1 : 0,
95+
transition: 'opacity 0.3s ease 0.1s',
96+
}}
97+
>
98+
{children}
99+
</div>
100+
</div>
101+
<style>{`
102+
@keyframes pulse {
103+
0%, 100% { opacity: 1; }
104+
50% { opacity: 0.5; }
105+
}
106+
`}</style>
107+
</div>
108+
)
109+
}
9110

10111
export function MarkdownRender(props) {
11112
return (
@@ -70,6 +171,8 @@ export function MarkdownRender(props) {
70171
'a',
71172
'pre',
72173
'cite',
174+
175+
'think',
73176
]}
74177
unwrapDisallowed={true}
75178
remarkPlugins={[remarkGfm, remarkBreaks]}
@@ -86,10 +189,11 @@ export function MarkdownRender(props) {
86189
components={{
87190
a: Hyperlink,
88191
pre: Pre,
192+
think: ThinkComponent,
89193
}}
90194
{...props}
91195
>
92-
{props.children}
196+
{props.children.replace('</think>', '\n\n</think>\n\n')}
93197
</ReactMarkdown>
94198
</div>
95199
)

src/components/MarkdownRender/markdown.jsx

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,108 @@ import remarkGfm from 'remark-gfm'
88
import remarkBreaks from 'remark-breaks'
99
import { Pre } from './Pre'
1010
import { Hyperlink } from './Hyperlink'
11-
import { memo } from 'react'
11+
import { memo, useState } from 'react'
12+
import { useTranslation } from 'react-i18next'
13+
14+
// eslint-disable-next-line
15+
const ThinkComponent = ({ node, children, ...props }) => {
16+
const { t } = useTranslation()
17+
const [isExpanded, setIsExpanded] = useState(true)
18+
const isEmpty =
19+
!children ||
20+
(Array.isArray(children) &&
21+
// eslint-disable-next-line
22+
(children.length === 0 ||
23+
// eslint-disable-next-line
24+
(children.length === 1 && typeof children[0] === 'string' && children[0].trim() === '')))
25+
26+
const toggleExpanded = () => {
27+
setIsExpanded(!isExpanded)
28+
}
29+
30+
return isEmpty ? (
31+
<></>
32+
) : (
33+
<div
34+
style={{
35+
marginBottom: '16px',
36+
borderRadius: '12px',
37+
border: '1px solid #e2e8f0',
38+
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.06)',
39+
overflow: 'hidden',
40+
transition: 'all 0.3s ease',
41+
}}
42+
>
43+
<div
44+
onClick={toggleExpanded}
45+
style={{
46+
cursor: 'pointer',
47+
padding: '12px 16px',
48+
borderBottom: isExpanded ? '1px solid rgba(255, 255, 255, 0.2)' : 'none',
49+
display: 'flex',
50+
alignItems: 'center',
51+
justifyContent: 'space-between',
52+
fontSize: '14px',
53+
fontWeight: '500',
54+
transition: 'all 0.3s ease',
55+
position: 'relative',
56+
}}
57+
>
58+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
59+
<span
60+
style={{
61+
display: 'inline-block',
62+
width: '6px',
63+
height: '6px',
64+
borderRadius: '50%',
65+
animation: isExpanded ? 'pulse 2s infinite' : 'none',
66+
}}
67+
/>
68+
<span style={{ fontSize: '13px', letterSpacing: '0.5px' }}>
69+
💭 {t('Thinking Content')}
70+
</span>
71+
</div>
72+
<div
73+
style={{
74+
transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',
75+
transition: 'transform 0.3s ease',
76+
fontSize: '12px',
77+
}}
78+
>
79+
80+
</div>
81+
</div>
82+
<div
83+
style={{
84+
maxHeight: isExpanded ? '1000px' : '0',
85+
overflow: 'hidden',
86+
transition: 'max-height 0.4s ease, padding 0.3s ease',
87+
padding: isExpanded ? '16px 20px' : '0 20px',
88+
borderTop: isExpanded ? '1px solid #e2e8f0' : 'none',
89+
}}
90+
>
91+
<div
92+
style={{
93+
whiteSpace: 'pre-wrap',
94+
fontSize: '13px',
95+
lineHeight: '1.6',
96+
fontFamily: '"SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace',
97+
opacity: isExpanded ? 1 : 0,
98+
transition: 'opacity 0.3s ease 0.1s',
99+
}}
100+
>
101+
{children}
102+
</div>
103+
</div>
104+
<style>{`
105+
@keyframes pulse {
106+
0%, 100% { opacity: 1; }
107+
50% { opacity: 0.5; }
108+
}
109+
`}</style>
110+
</div>
111+
)
112+
}
12113

13114
export function MarkdownRender(props) {
14115
return (
@@ -73,6 +174,8 @@ export function MarkdownRender(props) {
73174
'a',
74175
'pre',
75176
'cite',
177+
178+
'think',
76179
]}
77180
unwrapDisallowed={true}
78181
remarkPlugins={[remarkMath, remarkGfm, remarkBreaks]}
@@ -90,10 +193,11 @@ export function MarkdownRender(props) {
90193
components={{
91194
a: Hyperlink,
92195
pre: Pre,
196+
think: ThinkComponent,
93197
}}
94198
{...props}
95199
>
96-
{props.children}
200+
{props.children.replace('</think>', '\n\n</think>\n\n')}
97201
</ReactMarkdown>
98202
</div>
99203
)

0 commit comments

Comments
 (0)