Skip to content

Commit

Permalink
feat(perf): use remark and solid-markdown to render markdown
Browse files Browse the repository at this point in the history
  • Loading branch information
CNSeniorious000 committed Oct 1, 2024
1 parent ba3f83d commit 2fce175
Show file tree
Hide file tree
Showing 7 changed files with 801 additions and 127 deletions.
13 changes: 9 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,22 @@
"highlight.js": "^11.10.0",
"katex": "^0.16.11",
"lenis": "^1.1.13",
"markdown-it": "^14.1.0",
"markdown-it-highlightjs": "^4.2.0",
"markdown-it-katex": "^2.0.3",
"partial-json": "^0.1.7",
"rehype-highlight": "^7.0.0",
"rehype-katex": "^7.0.1",
"remark-breaks": "^4.0.0",
"remark-gfm": "^4.0.0",
"remark-math": "^6.0.0",
"remark-parse": "^11.0.0",
"reveal.js": "^5.1.0",
"solid-js": "^1.9.1",
"solid-markdown": "^2.0.13",
"solid-toast": "^0.5.0",
"solidjs-use": "^2.3.0",
"svelte": "^4.2.19",
"svelte-sonner": "^0.3.28",
"tiktoken": "^1.0.16"
"tiktoken": "^1.0.16",
"unified": "^11.0.5"
},
"devDependencies": {
"@evan-yang/eslint-config": "^1.0.9",
Expand Down
811 changes: 741 additions & 70 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions src/components/CodeBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useClipboard } from 'solidjs-use'
import type { SolidMarkdownComponents } from 'solid-markdown'

const CodeBlock: SolidMarkdownComponents['code'] = ({ children, inline }) => {
if (inline)
return <code>{children}</code>

const source = String(children)

const { copy, copied } = useClipboard({ copiedDuring: 1000 })

return (
<code class="group hljs block w-full overflow-x-scroll px-20px py-18px">
<button onClick={() => copy(source)} class="gap-1 text-sm gpt-copy-btn">
{copied() && <div class="text-sm font-sans">Copied!</div>}
<div class={copied() ? 'i-mingcute-copy-2-fill' : 'i-mingcute-copy-2-line'} />
</button>
{children}
</code>
)
}

export default CodeBlock
74 changes: 24 additions & 50 deletions src/components/MessageItem.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { createSignal } from 'solid-js'
import MarkdownIt from 'markdown-it'
import mdKatex from 'markdown-it-katex'
import mdHighlight from 'markdown-it-highlightjs'
import { useClipboard, useEventListener } from 'solidjs-use'
import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
import rehypeKatex from 'rehype-katex'
import rehypeHighlight from 'rehype-highlight'
import { SolidMarkdown } from 'solid-markdown'
import remarkBreaks from 'remark-breaks'
import { unified } from 'unified'
import remarkParse from 'remark-parse'
import IconRefresh from './icons/Refresh'
import CodeBlock from './CodeBlock'
import type { Accessor } from 'solid-js'
import type { ChatMessage } from '@/types'

Expand All @@ -22,22 +26,6 @@ export default ({ role, message, showRetry, onRetry }: Props) => {
user: 'bg-$c-fg-30',
assistant: 'bg-emerald-600/50 dark:bg-emerald-300 sm:(bg-gradient-to-br from-cyan-200 to-green-200)',
}
const [source] = createSignal('')
const { copy, copied } = useClipboard({ source, copiedDuring: 1000 })

useEventListener('click', (e) => {
const el = e.target as HTMLElement
let code = null

if (el.matches('[data-code]')) {
code = decodeURIComponent(el.dataset.code!)
copy(code)
}
if (el.matches('[data-code] > div')) {
code = decodeURIComponent(el.parentElement!.dataset.code!)
copy(code)
}
})

function heuristicPatch(markdown: string) {
const pattern = /(^|\n)```\S*$/
Expand All @@ -48,41 +36,27 @@ export default ({ role, message, showRetry, onRetry }: Props) => {
: markdown
}

const htmlString = () => {
const md = MarkdownIt({
linkify: true,
breaks: true,
}).use(mdKatex).use(mdHighlight)
const fence = md.renderer.rules.fence!
md.renderer.rules.fence = (...args) => {
const [tokens, idx] = args
const token = tokens[idx]
const rawCode = fence(...args)

return `<div class="relative group">
<div data-code=${encodeURIComponent(token.content)} class="gpt-copy-btn">
${copied() ? '<div mr-1 text-sm display-inline-block>Copied!</div><div i-mingcute-copy-2-fill></div>' : '<div i-mingcute-copy-2-line></div>'}
</div>
${rawCode}
</div>`
}

switch (typeof message) {
case 'function':
return md.render(heuristicPatch(message()))
case 'string':
return md.render(heuristicPatch(message))
default:
return ''
}
}
unified().use(remarkParse) // a weird workaround to fix a strange bug in solid-markdown that "setting on undefined" error

return (
<div class="px-20 transition-colors -mx-20 hover:bg-$c-fg-2 2xl:(px-20 -mx-20) md:(px-5 transition-background-color -mx-5)">
<div class="py-0.5 transition-padding 2xl:py-2 md:py-1">
<div class="flex gap-3.5 rounded-lg" class:op-75={role === 'user'} class:reverse-self-msg={role === 'user' && alignRightMine}>
<div class={`shrink-0 w-7 h-7 my-4 rounded-full op-80 ${roleClass[role]} <sm:w-1 <sm:h-auto <md:transition-background-color`} />
<div class="relative max-w-full overflow-hidden break-words prose <sm:text-3.6 message" innerHTML={htmlString()} />
<SolidMarkdown
renderingStrategy="reconcile"
remarkPlugins={[remarkGfm, remarkBreaks, remarkMath]}
rehypePlugins={[rehypeHighlight, rehypeKatex]}
class="relative max-w-full overflow-hidden break-words prose <sm:text-3.6 message"
components={{
code: CodeBlock,
pre({ children }) {
return <pre class="group overflow-hidden">{children}</pre>
},
}}
>
{heuristicPatch(typeof message === 'function' ? message() : message)}
</SolidMarkdown>
</div>
{showRetry?.() && onRetry && (
<div class="mb-2 fie px-3">
Expand Down
3 changes: 2 additions & 1 deletion src/message.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
.message pre {
background-color: #24242d;
font-size: 0.8rem;
padding: 0.4rem 0.6rem;
padding: 0;
position: relative;
}

.dark .message pre {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class API {

const res = await fetch(`${promplateBaseUrl}/single/suggest`, {
method: 'PUT',
body: JSON.stringify({ messages, model: 'llama3-70b-8192', prefill: true }),
body: JSON.stringify({ messages, model: 'llama-3.2-90b-text-preview', prefill: true }),
headers: { 'content-type': 'application/json' },
})

Expand Down
2 changes: 1 addition & 1 deletion uno.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default defineConfig({
'b-slate-link': 'border-b border-($c-fg-70 none) hover:border-dashed',
'gpt-title': 'text-2xl font-extrabold',
'gpt-subtitle': 'text-(2xl transparent) font-extrabold bg-(clip-text gradient-to-r) from-emerald-400 to-sky-200',
'gpt-copy-btn': 'absolute top-12px right-12px z-3 fcc border b-transparent w-fit min-w-8 h-8 p-2 bg-white/4 hover:bg-white/8 text-white/85 dark:(bg-$c-fg-5 hover:bg-$c-fg-10 text-$c-fg-90) cursor-pointer transition-all duration-150 active:scale-90 op-0 group-hover:op-100 rounded-1.1 backdrop-blur-10',
'gpt-copy-btn': 'absolute top-12px right-12px z-3 fcc border b-transparent h-8 p-2 bg-white/4 hover:bg-white/8 text-white/85 dark:(bg-$c-fg-5 hover:bg-$c-fg-10 text-$c-fg-90) transition-all duration-150 active:scale-90 op-0 group-hover:op-100 rounded-1.1 backdrop-blur-10',
'gpt-retry-btn': 'fi gap-1 px-2 py-0.5 op-70 ring-1.2 ring-$c-fg-50 rounded-md text-sm <sm:text-xs <sm:ring-$c-fg-30 cursor-pointer hover:bg-$c-fg-5 transition-background-color',
'gpt-back-top-btn': 'fcc text-base fixed bottom-17px right-17px sm:(bottom-20px right-20px) z-10 cursor-pointer',
'gpt-password-input': 'px-4 py-3 h-12 rounded-sm bg-(slate op-15) base-focus',
Expand Down

0 comments on commit 2fce175

Please sign in to comment.